• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2008 The RE2 Authors.  All Rights Reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 
5 // Regular expression engine tester -- test all the implementations against each other.
6 
7 #include "re2/testing/tester.h"
8 
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 
13 #include <string>
14 
15 #include "absl/base/macros.h"
16 #include "absl/flags/flag.h"
17 #include "absl/log/absl_check.h"
18 #include "absl/log/absl_log.h"
19 #include "absl/strings/escaping.h"
20 #include "absl/strings/str_format.h"
21 #include "absl/strings/string_view.h"
22 #include "re2/prog.h"
23 #include "re2/re2.h"
24 #include "re2/regexp.h"
25 #include "util/pcre.h"
26 
27 ABSL_FLAG(bool, dump_prog, false, "dump regexp program");
28 ABSL_FLAG(bool, log_okay, false, "log successful runs");
29 ABSL_FLAG(bool, dump_rprog, false, "dump reversed regexp program");
30 
31 ABSL_FLAG(int, max_regexp_failures, 100,
32           "maximum number of regexp test failures (-1 = unlimited)");
33 
34 ABSL_FLAG(std::string, regexp_engines, "",
35           "pattern to select regexp engines to test");
36 
37 namespace re2 {
38 
39 enum {
40   kMaxSubmatch = 1+16,  // $0...$16
41 };
42 
43 const char* engine_names[kEngineMax] = {
44   "Backtrack",
45   "NFA",
46   "DFA",
47   "DFA1",
48   "OnePass",
49   "BitState",
50   "RE2",
51   "RE2a",
52   "RE2b",
53   "PCRE",
54 };
55 
56 // Returns the name of the engine.
EngineName(Engine e)57 static const char* EngineName(Engine e) {
58   ABSL_CHECK_GE(e, 0);
59   ABSL_CHECK_LT(e, ABSL_ARRAYSIZE(engine_names));
60   ABSL_CHECK(engine_names[e] != NULL);
61   return engine_names[e];
62 }
63 
64 // Returns bit mask of engines to use.
Engines()65 static uint32_t Engines() {
66   static bool did_parse = false;
67   static uint32_t cached_engines = 0;
68 
69   if (did_parse)
70     return cached_engines;
71 
72   if (absl::GetFlag(FLAGS_regexp_engines).empty()) {
73     cached_engines = ~0;
74   } else {
75     for (Engine i = static_cast<Engine>(0); i < kEngineMax; i++)
76       if (absl::GetFlag(FLAGS_regexp_engines).find(EngineName(i)) != std::string::npos)
77         cached_engines |= 1<<i;
78   }
79 
80   if (cached_engines == 0)
81     ABSL_LOG(INFO) << "Warning: no engines enabled.";
82   if (!UsingPCRE)
83     cached_engines &= ~(1<<kEnginePCRE);
84   for (Engine i = static_cast<Engine>(0); i < kEngineMax; i++) {
85     if (cached_engines & (1<<i))
86       ABSL_LOG(INFO) << EngineName(i) << " enabled";
87   }
88 
89   did_parse = true;
90   return cached_engines;
91 }
92 
93 // The result of running a match.
94 struct TestInstance::Result {
Resultre2::TestInstance::Result95   Result()
96       : skipped(false),
97         matched(false),
98         untrusted(false),
99         have_submatch(false),
100         have_submatch0(false) {
101     ClearSubmatch();
102   }
103 
ClearSubmatchre2::TestInstance::Result104   void ClearSubmatch() {
105     for (int i = 0; i < kMaxSubmatch; i++)
106       submatch[i] = absl::string_view();
107   }
108 
109   bool skipped;         // test skipped: wasn't applicable
110   bool matched;         // found a match
111   bool untrusted;       // don't really trust the answer
112   bool have_submatch;   // computed all submatch info
113   bool have_submatch0;  // computed just submatch[0]
114   absl::string_view submatch[kMaxSubmatch];
115 };
116 
117 typedef TestInstance::Result Result;
118 
119 // Formats a single capture range s in text in the form (a,b)
120 // where a and b are the starting and ending offsets of s in text.
FormatCapture(absl::string_view text,absl::string_view s)121 static std::string FormatCapture(absl::string_view text,
122                                  absl::string_view s) {
123   if (s.data() == NULL)
124     return "(?,?)";
125   return absl::StrFormat("(%d,%d)",
126                          BeginPtr(s) - BeginPtr(text),
127                          EndPtr(s) - BeginPtr(text));
128 }
129 
130 // Returns whether text contains non-ASCII (>= 0x80) bytes.
NonASCII(absl::string_view text)131 static bool NonASCII(absl::string_view text) {
132   for (size_t i = 0; i < text.size(); i++)
133     if ((uint8_t)text[i] >= 0x80)
134       return true;
135   return false;
136 }
137 
138 // Returns string representation of match kind.
FormatKind(Prog::MatchKind kind)139 static std::string FormatKind(Prog::MatchKind kind) {
140   switch (kind) {
141     case Prog::kFullMatch:
142       return "full match";
143     case Prog::kLongestMatch:
144       return "longest match";
145     case Prog::kFirstMatch:
146       return "first match";
147     case Prog::kManyMatch:
148       return "many match";
149   }
150   return "???";
151 }
152 
153 // Returns string representation of anchor kind.
FormatAnchor(Prog::Anchor anchor)154 static std::string FormatAnchor(Prog::Anchor anchor) {
155   switch (anchor) {
156     case Prog::kAnchored:
157       return "anchored";
158     case Prog::kUnanchored:
159       return "unanchored";
160   }
161   return "???";
162 }
163 
164 struct ParseMode {
165   Regexp::ParseFlags parse_flags;
166   std::string desc;
167 };
168 
169 static const Regexp::ParseFlags single_line =
170   Regexp::LikePerl;
171 static const Regexp::ParseFlags multi_line =
172   static_cast<Regexp::ParseFlags>(Regexp::LikePerl & ~Regexp::OneLine);
173 
174 static ParseMode parse_modes[] = {
175   { single_line,                   "single-line"          },
176   { single_line|Regexp::Latin1,    "single-line, latin1"  },
177   { multi_line,                    "multiline"            },
178   { multi_line|Regexp::NonGreedy,  "multiline, nongreedy" },
179   { multi_line|Regexp::Latin1,     "multiline, latin1"    },
180 };
181 
FormatMode(Regexp::ParseFlags flags)182 static std::string FormatMode(Regexp::ParseFlags flags) {
183   for (size_t i = 0; i < ABSL_ARRAYSIZE(parse_modes); i++)
184     if (parse_modes[i].parse_flags == flags)
185       return parse_modes[i].desc;
186   return absl::StrFormat("%#x", static_cast<uint32_t>(flags));
187 }
188 
189 // Constructs and saves all the matching engines that
190 // will be required for the given tests.
TestInstance(absl::string_view regexp_str,Prog::MatchKind kind,Regexp::ParseFlags flags)191 TestInstance::TestInstance(absl::string_view regexp_str, Prog::MatchKind kind,
192                            Regexp::ParseFlags flags)
193   : regexp_str_(regexp_str),
194     kind_(kind),
195     flags_(flags),
196     error_(false),
197     regexp_(NULL),
198     num_captures_(0),
199     prog_(NULL),
200     rprog_(NULL),
201     re_(NULL),
202     re2_(NULL) {
203 
204   ABSL_VLOG(1) << absl::CEscape(regexp_str);
205 
206   // Compile regexp to prog.
207   // Always required - needed for backtracking (reference implementation).
208   RegexpStatus status;
209   regexp_ = Regexp::Parse(regexp_str, flags, &status);
210   if (regexp_ == NULL) {
211     ABSL_LOG(INFO) << "Cannot parse: " << absl::CEscape(regexp_str_)
212                    << " mode: " << FormatMode(flags);
213     error_ = true;
214     return;
215   }
216   num_captures_ = regexp_->NumCaptures();
217   prog_ = regexp_->CompileToProg(0);
218   if (prog_ == NULL) {
219     ABSL_LOG(INFO) << "Cannot compile: " << absl::CEscape(regexp_str_);
220     error_ = true;
221     return;
222   }
223   if (absl::GetFlag(FLAGS_dump_prog)) {
224     ABSL_LOG(INFO) << "Prog for "
225                    << " regexp "
226                    << absl::CEscape(regexp_str_)
227                    << " (" << FormatKind(kind_)
228                    << ", " << FormatMode(flags_)
229                    << ")\n"
230                    << prog_->Dump();
231   }
232 
233   // Compile regexp to reversed prog.  Only needed for DFA engines.
234   if (Engines() & ((1<<kEngineDFA)|(1<<kEngineDFA1))) {
235     rprog_ = regexp_->CompileToReverseProg(0);
236     if (rprog_ == NULL) {
237       ABSL_LOG(INFO) << "Cannot reverse compile: "
238                      << absl::CEscape(regexp_str_);
239       error_ = true;
240       return;
241     }
242     if (absl::GetFlag(FLAGS_dump_rprog))
243       ABSL_LOG(INFO) << rprog_->Dump();
244   }
245 
246   // Create re string that will be used for RE and RE2.
247   std::string re = std::string(regexp_str);
248   // Accomodate flags.
249   // Regexp::Latin1 will be accomodated below.
250   if (!(flags & Regexp::OneLine))
251     re = "(?m)" + re;
252   if (flags & Regexp::NonGreedy)
253     re = "(?U)" + re;
254   if (flags & Regexp::DotNL)
255     re = "(?s)" + re;
256 
257   // Compile regexp to RE2.
258   if (Engines() & ((1<<kEngineRE2)|(1<<kEngineRE2a)|(1<<kEngineRE2b))) {
259     RE2::Options options;
260     if (flags & Regexp::Latin1)
261       options.set_encoding(RE2::Options::EncodingLatin1);
262     if (kind_ == Prog::kLongestMatch)
263       options.set_longest_match(true);
264     re2_ = new RE2(re, options);
265     if (!re2_->error().empty()) {
266       ABSL_LOG(INFO) << "Cannot RE2: " << absl::CEscape(re);
267       error_ = true;
268       return;
269     }
270   }
271 
272   // Compile regexp to RE.
273   // PCRE as exposed by the RE interface isn't always usable.
274   // 1. It disagrees about handling of empty-string reptitions
275   //    like matching (a*)* against "b".  PCRE treats the (a*) as
276   //    occurring once, while we treat it as occurring not at all.
277   // 2. It treats $ as this weird thing meaning end of string
278   //    or before the \n at the end of the string.
279   // 3. It doesn't implement POSIX leftmost-longest matching.
280   // 4. It lets \s match vertical tab.
281   // MimicsPCRE() detects 1 and 2.
282   if ((Engines() & (1<<kEnginePCRE)) && regexp_->MimicsPCRE() &&
283       kind_ != Prog::kLongestMatch) {
284     PCRE_Options o;
285     o.set_option(PCRE::UTF8);
286     if (flags & Regexp::Latin1)
287       o.set_option(PCRE::None);
288     // PCRE has interface bug keeping us from finding $0, so
289     // add one more layer of parens.
290     re_ = new PCRE("("+re+")", o);
291     if (!re_->error().empty()) {
292       ABSL_LOG(INFO) << "Cannot PCRE: " << absl::CEscape(re);
293       error_ = true;
294       return;
295     }
296   }
297 }
298 
~TestInstance()299 TestInstance::~TestInstance() {
300   if (regexp_)
301     regexp_->Decref();
302   delete prog_;
303   delete rprog_;
304   delete re_;
305   delete re2_;
306 }
307 
308 // Runs a single search using the named engine type.
309 // This interface hides all the irregularities of the various
310 // engine interfaces from the rest of this file.
RunSearch(Engine type,absl::string_view orig_text,absl::string_view orig_context,Prog::Anchor anchor,Result * result)311 void TestInstance::RunSearch(Engine type, absl::string_view orig_text,
312                              absl::string_view orig_context,
313                              Prog::Anchor anchor, Result* result) {
314   if (regexp_ == NULL) {
315     result->skipped = true;
316     return;
317   }
318   int nsubmatch = 1 + num_captures_;  // NumCaptures doesn't count $0
319   if (nsubmatch > kMaxSubmatch)
320     nsubmatch = kMaxSubmatch;
321 
322   absl::string_view text = orig_text;
323   absl::string_view context = orig_context;
324 
325   switch (type) {
326     default:
327       ABSL_LOG(FATAL) << "Bad RunSearch type: " << (int)type;
328 
329     case kEngineBacktrack:
330       if (prog_ == NULL) {
331         result->skipped = true;
332         break;
333       }
334       result->matched =
335         prog_->UnsafeSearchBacktrack(text, context, anchor, kind_,
336                                      result->submatch, nsubmatch);
337       result->have_submatch = true;
338       break;
339 
340     case kEngineNFA:
341       if (prog_ == NULL) {
342         result->skipped = true;
343         break;
344       }
345       result->matched =
346         prog_->SearchNFA(text, context, anchor, kind_,
347                         result->submatch, nsubmatch);
348       result->have_submatch = true;
349       break;
350 
351     case kEngineDFA:
352       if (prog_ == NULL) {
353         result->skipped = true;
354         break;
355       }
356       result->matched = prog_->SearchDFA(text, context, anchor, kind_, NULL,
357                                          &result->skipped, NULL);
358       break;
359 
360     case kEngineDFA1:
361       if (prog_ == NULL || rprog_ == NULL) {
362         result->skipped = true;
363         break;
364       }
365       result->matched =
366         prog_->SearchDFA(text, context, anchor, kind_, result->submatch,
367                          &result->skipped, NULL);
368       // If anchored, no need for second run,
369       // but do it anyway to find more bugs.
370       if (result->matched) {
371         if (!rprog_->SearchDFA(result->submatch[0], context,
372                                Prog::kAnchored, Prog::kLongestMatch,
373                                result->submatch,
374                                &result->skipped, NULL)) {
375           ABSL_LOG(ERROR) << "Reverse DFA inconsistency: "
376                           << absl::CEscape(regexp_str_)
377                           << " on " << absl::CEscape(text);
378           result->matched = false;
379         }
380       }
381       result->have_submatch0 = true;
382       break;
383 
384     case kEngineOnePass:
385       if (prog_ == NULL ||
386           !prog_->IsOnePass() ||
387           anchor == Prog::kUnanchored ||
388           nsubmatch > Prog::kMaxOnePassCapture) {
389         result->skipped = true;
390         break;
391       }
392       result->matched = prog_->SearchOnePass(text, context, anchor, kind_,
393                                       result->submatch, nsubmatch);
394       result->have_submatch = true;
395       break;
396 
397     case kEngineBitState:
398       if (prog_ == NULL ||
399           !prog_->CanBitState()) {
400         result->skipped = true;
401         break;
402       }
403       result->matched = prog_->SearchBitState(text, context, anchor, kind_,
404                                               result->submatch, nsubmatch);
405       result->have_submatch = true;
406       break;
407 
408     case kEngineRE2:
409     case kEngineRE2a:
410     case kEngineRE2b: {
411       if (!re2_ || EndPtr(text) != EndPtr(context)) {
412         result->skipped = true;
413         break;
414       }
415 
416       RE2::Anchor re_anchor;
417       if (anchor == Prog::kAnchored)
418         re_anchor = RE2::ANCHOR_START;
419       else
420         re_anchor = RE2::UNANCHORED;
421       if (kind_ == Prog::kFullMatch)
422         re_anchor = RE2::ANCHOR_BOTH;
423 
424       result->matched = re2_->Match(
425           context,
426           static_cast<size_t>(BeginPtr(text) - BeginPtr(context)),
427           static_cast<size_t>(EndPtr(text) - BeginPtr(context)),
428           re_anchor,
429           result->submatch,
430           nsubmatch);
431       result->have_submatch = nsubmatch > 0;
432       break;
433     }
434 
435     case kEnginePCRE: {
436       if (!re_ || BeginPtr(text) != BeginPtr(context) ||
437           EndPtr(text) != EndPtr(context)) {
438         result->skipped = true;
439         break;
440       }
441 
442       // In Perl/PCRE, \v matches any character considered vertical
443       // whitespace, not just vertical tab. Regexp::MimicsPCRE() is
444       // unable to handle all cases of this, unfortunately, so just
445       // catch them here. :(
446       if (regexp_str_.find("\\v") != absl::string_view::npos &&
447           (text.find('\n') != absl::string_view::npos ||
448            text.find('\f') != absl::string_view::npos ||
449            text.find('\r') != absl::string_view::npos)) {
450         result->skipped = true;
451         break;
452       }
453 
454       // PCRE 8.34 or so started allowing vertical tab to match \s,
455       // following a change made in Perl 5.18. RE2 does not.
456       if ((regexp_str_.find("\\s") != absl::string_view::npos ||
457            regexp_str_.find("\\S") != absl::string_view::npos) &&
458           text.find('\v') != absl::string_view::npos) {
459         result->skipped = true;
460         break;
461       }
462 
463       const PCRE::Arg **argptr = new const PCRE::Arg*[nsubmatch];
464       PCRE::Arg *a = new PCRE::Arg[nsubmatch];
465       for (int i = 0; i < nsubmatch; i++) {
466         a[i] = PCRE::Arg(&result->submatch[i]);
467         argptr[i] = &a[i];
468       }
469       size_t consumed;
470       PCRE::Anchor pcre_anchor;
471       if (anchor == Prog::kAnchored)
472         pcre_anchor = PCRE::ANCHOR_START;
473       else
474         pcre_anchor = PCRE::UNANCHORED;
475       if (kind_ == Prog::kFullMatch)
476         pcre_anchor = PCRE::ANCHOR_BOTH;
477       re_->ClearHitLimit();
478       result->matched =
479         re_->DoMatch(text,
480                      pcre_anchor,
481                      &consumed,
482                      argptr, nsubmatch);
483       if (re_->HitLimit()) {
484         result->untrusted = true;
485         delete[] argptr;
486         delete[] a;
487         break;
488       }
489       result->have_submatch = true;
490       delete[] argptr;
491       delete[] a;
492       break;
493     }
494   }
495 
496   if (!result->matched)
497     result->ClearSubmatch();
498 }
499 
500 // Checks whether r is okay given that correct is the right answer.
501 // Specifically, r's answers have to match (but it doesn't have to
502 // claim to have all the answers).
ResultOkay(const Result & r,const Result & correct)503 static bool ResultOkay(const Result& r, const Result& correct) {
504   if (r.skipped)
505     return true;
506   if (r.matched != correct.matched)
507     return false;
508   if (r.have_submatch || r.have_submatch0) {
509     for (int i = 0; i < kMaxSubmatch; i++) {
510       if (correct.submatch[i].data() != r.submatch[i].data() ||
511           correct.submatch[i].size() != r.submatch[i].size())
512         return false;
513       if (!r.have_submatch)
514         break;
515     }
516   }
517   return true;
518 }
519 
520 // Runs a single test.
RunCase(absl::string_view text,absl::string_view context,Prog::Anchor anchor)521 bool TestInstance::RunCase(absl::string_view text, absl::string_view context,
522                            Prog::Anchor anchor) {
523   // Backtracking is the gold standard.
524   Result correct;
525   RunSearch(kEngineBacktrack, text, context, anchor, &correct);
526   if (correct.skipped) {
527     if (regexp_ == NULL)
528       return true;
529     ABSL_LOG(ERROR) << "Skipped backtracking! " << absl::CEscape(regexp_str_)
530                     << " " << FormatMode(flags_);
531     return false;
532   }
533   ABSL_VLOG(1) << "Try: regexp " << absl::CEscape(regexp_str_)
534                << " text " << absl::CEscape(text)
535                << " (" << FormatKind(kind_)
536                << ", " << FormatAnchor(anchor)
537                << ", " << FormatMode(flags_)
538                << ")";
539 
540   // Compare the others.
541   bool all_okay = true;
542   for (Engine i = kEngineBacktrack+1; i < kEngineMax; i++) {
543     if (!(Engines() & (1<<i)))
544       continue;
545 
546     Result r;
547     RunSearch(i, text, context, anchor, &r);
548     if (ResultOkay(r, correct)) {
549       if (absl::GetFlag(FLAGS_log_okay))
550         LogMatch(r.skipped ? "Skipped: " : "Okay: ", i, text, context, anchor);
551       continue;
552     }
553 
554     // We disagree with PCRE on the meaning of some Unicode matches.
555     // In particular, we treat non-ASCII UTF-8 as non-word characters.
556     // We also treat "empty" character sets like [^\w\W] as being
557     // impossible to match, while PCRE apparently excludes some code
558     // points (e.g., 0x0080) from both \w and \W.
559     if (i == kEnginePCRE && NonASCII(text))
560       continue;
561 
562     if (!r.untrusted)
563       all_okay = false;
564 
565     LogMatch(r.untrusted ? "(Untrusted) Mismatch: " : "Mismatch: ", i, text,
566              context, anchor);
567     if (r.matched != correct.matched) {
568       if (r.matched) {
569         ABSL_LOG(INFO) << "   Should not match (but does).";
570       } else {
571         ABSL_LOG(INFO) << "   Should match (but does not).";
572         continue;
573       }
574     }
575     for (int i = 0; i < 1+num_captures_; i++) {
576       if (r.submatch[i].data() != correct.submatch[i].data() ||
577           r.submatch[i].size() != correct.submatch[i].size()) {
578         ABSL_LOG(INFO) <<
579           absl::StrFormat("   $%d: should be %s is %s",
580                           i,
581                           FormatCapture(text, correct.submatch[i]),
582                           FormatCapture(text, r.submatch[i]));
583       } else {
584         ABSL_LOG(INFO) <<
585           absl::StrFormat("   $%d: %s ok", i,
586                           FormatCapture(text, r.submatch[i]));
587       }
588     }
589   }
590 
591   if (!all_okay) {
592     // This will be initialised once (after flags have been initialised)
593     // and that is desirable because we want to enforce a global limit.
594     static int max_regexp_failures = absl::GetFlag(FLAGS_max_regexp_failures);
595     if (max_regexp_failures > 0 && --max_regexp_failures == 0)
596       ABSL_LOG(QFATAL) << "Too many regexp failures.";
597   }
598 
599   return all_okay;
600 }
601 
LogMatch(const char * prefix,Engine e,absl::string_view text,absl::string_view context,Prog::Anchor anchor)602 void TestInstance::LogMatch(const char* prefix, Engine e,
603                             absl::string_view text, absl::string_view context,
604                             Prog::Anchor anchor) {
605   ABSL_LOG(INFO) << prefix
606     << EngineName(e)
607     << " regexp "
608     << absl::CEscape(regexp_str_)
609     << " "
610     << absl::CEscape(regexp_->ToString())
611     << " text "
612     << absl::CEscape(text)
613     << " ("
614     << BeginPtr(text) - BeginPtr(context)
615     << ","
616     << EndPtr(text) - BeginPtr(context)
617     << ") of context "
618     << absl::CEscape(context)
619     << " (" << FormatKind(kind_)
620     << ", " << FormatAnchor(anchor)
621     << ", " << FormatMode(flags_)
622     << ")";
623 }
624 
625 static Prog::MatchKind kinds[] = {
626   Prog::kFirstMatch,
627   Prog::kLongestMatch,
628   Prog::kFullMatch,
629 };
630 
631 // Test all possible match kinds and parse modes.
Tester(absl::string_view regexp)632 Tester::Tester(absl::string_view regexp) {
633   error_ = false;
634   for (size_t i = 0; i < ABSL_ARRAYSIZE(kinds); i++) {
635     for (size_t j = 0; j < ABSL_ARRAYSIZE(parse_modes); j++) {
636       TestInstance* t = new TestInstance(regexp, kinds[i],
637                                          parse_modes[j].parse_flags);
638       error_ |= t->error();
639       v_.push_back(t);
640     }
641   }
642 }
643 
~Tester()644 Tester::~Tester() {
645   for (size_t i = 0; i < v_.size(); i++)
646     delete v_[i];
647 }
648 
TestCase(absl::string_view text,absl::string_view context,Prog::Anchor anchor)649 bool Tester::TestCase(absl::string_view text, absl::string_view context,
650                       Prog::Anchor anchor) {
651   bool okay = true;
652   for (size_t i = 0; i < v_.size(); i++)
653     okay &= (!v_[i]->error() && v_[i]->RunCase(text, context, anchor));
654   return okay;
655 }
656 
657 static Prog::Anchor anchors[] = {
658   Prog::kAnchored,
659   Prog::kUnanchored
660 };
661 
TestInput(absl::string_view text)662 bool Tester::TestInput(absl::string_view text) {
663   bool okay = TestInputInContext(text, text);
664   if (!text.empty()) {
665     absl::string_view sp;
666     sp = text;
667     sp.remove_prefix(1);
668     okay &= TestInputInContext(sp, text);
669     sp = text;
670     sp.remove_suffix(1);
671     okay &= TestInputInContext(sp, text);
672   }
673   return okay;
674 }
675 
TestInputInContext(absl::string_view text,absl::string_view context)676 bool Tester::TestInputInContext(absl::string_view text,
677                                 absl::string_view context) {
678   bool okay = true;
679   for (size_t i = 0; i < ABSL_ARRAYSIZE(anchors); i++)
680     okay &= TestCase(text, context, anchors[i]);
681   return okay;
682 }
683 
TestRegexpOnText(absl::string_view regexp,absl::string_view text)684 bool TestRegexpOnText(absl::string_view regexp,
685                       absl::string_view text) {
686   Tester t(regexp);
687   return t.TestInput(text);
688 }
689 
690 }  // namespace re2
691