Regex.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*
  2. * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/TestSuite.h> // import first, to prevent warning of ASSERT* redefinition
  27. #include <AK/StringBuilder.h>
  28. #include <LibRegex/Regex.h>
  29. #include <LibRegex/RegexDebug.h>
  30. #include <stdio.h>
  31. static ECMAScriptOptions match_test_api_options(const ECMAScriptOptions options)
  32. {
  33. return options;
  34. }
  35. static PosixOptions match_test_api_options(const PosixOptions options)
  36. {
  37. return options;
  38. }
  39. TEST_CASE(regex_options_ecmascript)
  40. {
  41. ECMAScriptOptions eo;
  42. eo |= ECMAScriptFlags::Global;
  43. EXPECT(eo & ECMAScriptFlags::Global);
  44. EXPECT(!(eo & ECMAScriptFlags::Insensitive));
  45. eo = match_test_api_options(ECMAScriptFlags::Global | ECMAScriptFlags::Insensitive | ECMAScriptFlags::Sticky);
  46. EXPECT(eo & ECMAScriptFlags::Global);
  47. EXPECT(eo & ECMAScriptFlags::Insensitive);
  48. EXPECT(eo & ECMAScriptFlags::Sticky);
  49. EXPECT(!(eo & ECMAScriptFlags::Unicode));
  50. EXPECT(!(eo & ECMAScriptFlags::Multiline));
  51. EXPECT(!(eo & ECMAScriptFlags::SingleLine));
  52. eo &= ECMAScriptFlags::Insensitive;
  53. EXPECT(!(eo & ECMAScriptFlags::Global));
  54. EXPECT(eo & ECMAScriptFlags::Insensitive);
  55. EXPECT(!(eo & ECMAScriptFlags::Multiline));
  56. eo &= ECMAScriptFlags::Sticky;
  57. EXPECT(!(eo & ECMAScriptFlags::Global));
  58. EXPECT(!(eo & ECMAScriptFlags::Insensitive));
  59. EXPECT(!(eo & ECMAScriptFlags::Multiline));
  60. EXPECT(!(eo & ECMAScriptFlags::Sticky));
  61. eo = ~ECMAScriptFlags::Insensitive;
  62. EXPECT(eo & ECMAScriptFlags::Global);
  63. EXPECT(!(eo & ECMAScriptFlags::Insensitive));
  64. EXPECT(eo & ECMAScriptFlags::Multiline);
  65. EXPECT(eo & ECMAScriptFlags::Sticky);
  66. }
  67. TEST_CASE(regex_options_posix)
  68. {
  69. PosixOptions eo;
  70. eo |= PosixFlags::Global;
  71. EXPECT(eo & PosixFlags::Global);
  72. EXPECT(!(eo & PosixFlags::Insensitive));
  73. eo = match_test_api_options(PosixFlags::Global | PosixFlags::Insensitive | PosixFlags::MatchNotBeginOfLine);
  74. EXPECT(eo & PosixFlags::Global);
  75. EXPECT(eo & PosixFlags::Insensitive);
  76. EXPECT(eo & PosixFlags::MatchNotBeginOfLine);
  77. EXPECT(!(eo & PosixFlags::Unicode));
  78. EXPECT(!(eo & PosixFlags::Multiline));
  79. eo &= PosixFlags::Insensitive;
  80. EXPECT(!(eo & PosixFlags::Global));
  81. EXPECT(eo & PosixFlags::Insensitive);
  82. EXPECT(!(eo & PosixFlags::Multiline));
  83. eo &= PosixFlags::MatchNotBeginOfLine;
  84. EXPECT(!(eo & PosixFlags::Global));
  85. EXPECT(!(eo & PosixFlags::Insensitive));
  86. EXPECT(!(eo & PosixFlags::Multiline));
  87. eo = ~PosixFlags::Insensitive;
  88. EXPECT(eo & PosixFlags::Global);
  89. EXPECT(!(eo & PosixFlags::Insensitive));
  90. EXPECT(eo & PosixFlags::Multiline);
  91. }
  92. TEST_CASE(regex_lexer)
  93. {
  94. Lexer l("/[.*+?^${}()|[\\]\\\\]/g");
  95. EXPECT(l.next().type() == regex::TokenType::Slash);
  96. EXPECT(l.next().type() == regex::TokenType::LeftBracket);
  97. EXPECT(l.next().type() == regex::TokenType::Period);
  98. EXPECT(l.next().type() == regex::TokenType::Asterisk);
  99. EXPECT(l.next().type() == regex::TokenType::Plus);
  100. EXPECT(l.next().type() == regex::TokenType::Questionmark);
  101. EXPECT(l.next().type() == regex::TokenType::Circumflex);
  102. EXPECT(l.next().type() == regex::TokenType::Dollar);
  103. EXPECT(l.next().type() == regex::TokenType::LeftCurly);
  104. EXPECT(l.next().type() == regex::TokenType::RightCurly);
  105. EXPECT(l.next().type() == regex::TokenType::LeftParen);
  106. EXPECT(l.next().type() == regex::TokenType::RightParen);
  107. EXPECT(l.next().type() == regex::TokenType::Pipe);
  108. EXPECT(l.next().type() == regex::TokenType::LeftBracket);
  109. EXPECT(l.next().type() == regex::TokenType::EscapeSequence);
  110. EXPECT(l.next().type() == regex::TokenType::EscapeSequence);
  111. EXPECT(l.next().type() == regex::TokenType::RightBracket);
  112. EXPECT(l.next().type() == regex::TokenType::Slash);
  113. EXPECT(l.next().type() == regex::TokenType::Char);
  114. }
  115. TEST_CASE(parser_error_parens)
  116. {
  117. String pattern = "test()test";
  118. Lexer l(pattern);
  119. PosixExtendedParser p(l);
  120. p.parse();
  121. EXPECT(p.has_error());
  122. EXPECT(p.error() == Error::EmptySubExpression);
  123. }
  124. TEST_CASE(parser_error_special_characters_used_at_wrong_place)
  125. {
  126. String pattern;
  127. Vector<char, 5> chars = { '*', '+', '?', '{' };
  128. StringBuilder b;
  129. Lexer l;
  130. PosixExtended p(l);
  131. for (auto& ch : chars) {
  132. // First in ere
  133. b.clear();
  134. b.append(ch);
  135. pattern = b.build();
  136. l.set_source(pattern);
  137. p.parse();
  138. EXPECT(p.has_error());
  139. EXPECT(p.error() == Error::InvalidRepetitionMarker);
  140. // After vertical line
  141. b.clear();
  142. b.append("a|");
  143. b.append(ch);
  144. pattern = b.build();
  145. l.set_source(pattern);
  146. p.parse();
  147. EXPECT(p.has_error());
  148. EXPECT(p.error() == Error::InvalidRepetitionMarker);
  149. // After circumflex
  150. b.clear();
  151. b.append("^");
  152. b.append(ch);
  153. pattern = b.build();
  154. l.set_source(pattern);
  155. p.parse();
  156. EXPECT(p.has_error());
  157. EXPECT(p.error() == Error::InvalidRepetitionMarker);
  158. // After dollar
  159. b.clear();
  160. b.append("$");
  161. b.append(ch);
  162. pattern = b.build();
  163. l.set_source(pattern);
  164. p.parse();
  165. EXPECT(p.has_error());
  166. EXPECT(p.error() == Error::InvalidRepetitionMarker);
  167. // After left parens
  168. b.clear();
  169. b.append("(");
  170. b.append(ch);
  171. b.append(")");
  172. pattern = b.build();
  173. l.set_source(pattern);
  174. p.parse();
  175. EXPECT(p.has_error());
  176. EXPECT(p.error() == Error::InvalidRepetitionMarker);
  177. }
  178. }
  179. TEST_CASE(parser_error_vertical_line_used_at_wrong_place)
  180. {
  181. Lexer l;
  182. PosixExtended p(l);
  183. // First in ere
  184. l.set_source("|asdf");
  185. p.parse();
  186. EXPECT(p.has_error());
  187. EXPECT(p.error() == Error::EmptySubExpression);
  188. // Last in ere
  189. l.set_source("asdf|");
  190. p.parse();
  191. EXPECT(p.has_error());
  192. EXPECT(p.error() == Error::EmptySubExpression);
  193. // After left parens
  194. l.set_source("(|asdf)");
  195. p.parse();
  196. EXPECT(p.has_error());
  197. EXPECT(p.error() == Error::EmptySubExpression);
  198. // Proceed right parens
  199. l.set_source("(asdf)|");
  200. p.parse();
  201. EXPECT(p.has_error());
  202. EXPECT(p.error() == Error::EmptySubExpression);
  203. }
  204. TEST_CASE(catch_all_first)
  205. {
  206. Regex<PosixExtended> re("^.*$");
  207. RegexResult m;
  208. re.match("Hello World", m);
  209. EXPECT(m.count == 1);
  210. EXPECT(re.match("Hello World", m));
  211. }
  212. TEST_CASE(catch_all)
  213. {
  214. Regex<PosixExtended> re("^.*$", PosixFlags::Global);
  215. EXPECT(re.has_match("Hello World"));
  216. EXPECT(re.match("Hello World").success);
  217. EXPECT(re.match("Hello World").count == 1);
  218. EXPECT(has_match("Hello World", re));
  219. auto res = match("Hello World", re);
  220. EXPECT(res.success);
  221. EXPECT(res.count == 1);
  222. EXPECT(res.matches.size() == 1);
  223. EXPECT(res.matches.first().view == "Hello World");
  224. }
  225. TEST_CASE(catch_all_again)
  226. {
  227. Regex<PosixExtended> re("^.*$", PosixFlags::Extra);
  228. EXPECT_EQ(has_match("Hello World", re), true);
  229. }
  230. TEST_CASE(char_utf8)
  231. {
  232. Regex<PosixExtended> re("😀");
  233. RegexResult result;
  234. EXPECT_EQ((result = match("Привет, мир! 😀 γειά σου κόσμος 😀 こんにちは世界", re, PosixFlags::Global)).success, true);
  235. EXPECT_EQ(result.count, 2u);
  236. }
  237. TEST_CASE(catch_all_newline)
  238. {
  239. Regex<PosixExtended> re("^.*$", PosixFlags::Multiline | PosixFlags::StringCopyMatches);
  240. RegexResult result;
  241. auto lambda = [&result, &re]() {
  242. String aaa = "Hello World\nTest\n1234\n";
  243. result = match(aaa, re);
  244. EXPECT_EQ(result.success, true);
  245. };
  246. lambda();
  247. EXPECT_EQ(result.count, 3u);
  248. EXPECT_EQ(result.matches.at(0).view, "Hello World");
  249. EXPECT_EQ(result.matches.at(1).view, "Test");
  250. EXPECT_EQ(result.matches.at(2).view, "1234");
  251. }
  252. TEST_CASE(catch_all_newline_view)
  253. {
  254. Regex<PosixExtended> re("^.*$", PosixFlags::Multiline);
  255. RegexResult result;
  256. String aaa = "Hello World\nTest\n1234\n";
  257. result = match(aaa, re);
  258. EXPECT_EQ(result.success, true);
  259. EXPECT_EQ(result.count, 3u);
  260. String str = "Hello World";
  261. EXPECT_EQ(result.matches.at(0).view, str.view());
  262. EXPECT_EQ(result.matches.at(1).view, "Test");
  263. EXPECT_EQ(result.matches.at(2).view, "1234");
  264. }
  265. TEST_CASE(catch_all_newline_2)
  266. {
  267. Regex<PosixExtended> re("^.*$");
  268. RegexResult result;
  269. result = match("Hello World\nTest\n1234\n", re, PosixFlags::Multiline | PosixFlags::StringCopyMatches);
  270. EXPECT_EQ(result.success, true);
  271. EXPECT_EQ(result.count, 3u);
  272. EXPECT_EQ(result.matches.at(0).view, "Hello World");
  273. EXPECT_EQ(result.matches.at(1).view, "Test");
  274. EXPECT_EQ(result.matches.at(2).view, "1234");
  275. result = match("Hello World\nTest\n1234\n", re);
  276. EXPECT_EQ(result.success, true);
  277. EXPECT_EQ(result.count, 1u);
  278. EXPECT_EQ(result.matches.at(0).view, "Hello World\nTest\n1234\n");
  279. }
  280. TEST_CASE(match_all_character_class)
  281. {
  282. Regex<PosixExtended> re("[[:alpha:]]");
  283. String str = "[Window]\nOpacity=255\nAudibleBeep=0\n";
  284. RegexResult result = match(str, re, PosixFlags::Global | PosixFlags::StringCopyMatches);
  285. EXPECT_EQ(result.success, true);
  286. EXPECT_EQ(result.count, 24u);
  287. EXPECT_EQ(result.matches.at(0).view, "W");
  288. EXPECT_EQ(result.matches.at(1).view, "i");
  289. EXPECT_EQ(result.matches.at(2).view, "n");
  290. EXPECT(&result.matches.at(0).view.characters_without_null_termination()[0] != &str.view().characters_without_null_termination()[1]);
  291. }
  292. TEST_CASE(match_character_class_with_assertion)
  293. {
  294. Regex<PosixExtended> re("[[:alpha:]]+$");
  295. String str = "abcdef";
  296. RegexResult result = match(str, re);
  297. EXPECT_EQ(result.success, true);
  298. EXPECT_EQ(result.count, 1u);
  299. }
  300. TEST_CASE(example_for_git_commit)
  301. {
  302. Regex<PosixExtended> re("^.*$");
  303. auto result = re.match("Well, hello friends!\nHello World!");
  304. EXPECT(result.success);
  305. EXPECT(result.count == 1);
  306. EXPECT(result.matches.at(0).view.starts_with("Well"));
  307. EXPECT(result.matches.at(0).view.length() == 33);
  308. EXPECT(re.has_match("Well,...."));
  309. result = re.match("Well, hello friends!\nHello World!", PosixFlags::Multiline);
  310. EXPECT(result.success);
  311. EXPECT(result.count == 2);
  312. EXPECT(result.matches.at(0).view == "Well, hello friends!");
  313. EXPECT(result.matches.at(1).view == "Hello World!");
  314. }
  315. TEST_CASE(email_address)
  316. {
  317. Regex<PosixExtended> re("^[A-Z0-9a-z._%+-]{1,64}@([A-Za-z0-9-]{1,63}\\.){1,125}[A-Za-z]{2,63}$");
  318. EXPECT(re.has_match("hello.world@domain.tld"));
  319. EXPECT(re.has_match("this.is.a.very_long_email_address@world.wide.web"));
  320. }
  321. TEST_CASE(ini_file_entries)
  322. {
  323. Regex<PosixExtended> re("[[:alpha:]]*=([[:digit:]]*)|\\[(.*)\\]");
  324. RegexResult result;
  325. #ifdef REGEX_DEBUG
  326. RegexDebug regex_dbg(stderr);
  327. regex_dbg.print_raw_bytecode(re);
  328. regex_dbg.print_header();
  329. regex_dbg.print_bytecode(re);
  330. #endif
  331. String haystack = "[Window]\nOpacity=255\nAudibleBeep=0\n";
  332. EXPECT_EQ(re.search(haystack.view(), result, PosixFlags::Multiline), true);
  333. EXPECT_EQ(result.count, 3u);
  334. #ifdef REGEX_DEBUG
  335. for (auto& v : result.matches)
  336. fprintf(stderr, "%s\n", v.view.to_string().characters());
  337. #endif
  338. EXPECT_EQ(result.matches.at(0).view, "[Window]");
  339. EXPECT_EQ(result.capture_group_matches.at(0).at(0).view, "Window");
  340. EXPECT_EQ(result.matches.at(1).view, "Opacity=255");
  341. EXPECT_EQ(result.matches.at(1).line, 1u);
  342. EXPECT_EQ(result.matches.at(1).column, 0u);
  343. EXPECT_EQ(result.capture_group_matches.at(1).at(0).view, "255");
  344. EXPECT_EQ(result.capture_group_matches.at(1).at(0).line, 1u);
  345. EXPECT_EQ(result.capture_group_matches.at(1).at(0).column, 8u);
  346. EXPECT_EQ(result.matches.at(2).view, "AudibleBeep=0");
  347. EXPECT_EQ(result.capture_group_matches.at(2).at(0).view, "0");
  348. EXPECT_EQ(result.capture_group_matches.at(2).at(0).line, 2u);
  349. EXPECT_EQ(result.capture_group_matches.at(2).at(0).column, 12u);
  350. }
  351. TEST_CASE(ini_file_entries2)
  352. {
  353. Regex<PosixExtended> re("[[:alpha:]]*=([[:digit:]]*)");
  354. RegexResult result;
  355. String haystack = "ViewMode=Icon";
  356. EXPECT_EQ(re.match(haystack.view(), result), false);
  357. EXPECT_EQ(result.count, 0u);
  358. EXPECT_EQ(re.search(haystack.view(), result), true);
  359. EXPECT_EQ(result.count, 1u);
  360. }
  361. TEST_CASE(named_capture_group)
  362. {
  363. Regex<PosixExtended> re("[[:alpha:]]*=(?<Test>[[:digit:]]*)");
  364. RegexResult result;
  365. #ifdef REGEX_DEBUG
  366. RegexDebug regex_dbg(stderr);
  367. regex_dbg.print_raw_bytecode(re);
  368. regex_dbg.print_header();
  369. regex_dbg.print_bytecode(re);
  370. #endif
  371. String haystack = "[Window]\nOpacity=255\nAudibleBeep=0\n";
  372. EXPECT_EQ(re.search(haystack, result, PosixFlags::Multiline), true);
  373. EXPECT_EQ(result.count, 2u);
  374. EXPECT_EQ(result.matches.at(0).view, "Opacity=255");
  375. EXPECT_EQ(result.named_capture_group_matches.at(0).ensure("Test").view, "255");
  376. EXPECT_EQ(result.matches.at(1).view, "AudibleBeep=0");
  377. EXPECT_EQ(result.named_capture_group_matches.at(1).ensure("Test").view, "0");
  378. }
  379. TEST_CASE(a_star)
  380. {
  381. Regex<PosixExtended> re("a*");
  382. RegexResult result;
  383. #ifdef REGEX_DEBUG
  384. RegexDebug regex_dbg(stderr);
  385. regex_dbg.print_raw_bytecode(re);
  386. regex_dbg.print_header();
  387. regex_dbg.print_bytecode(re);
  388. #endif
  389. String haystack = "[Window]\nOpacity=255\nAudibleBeep=0\n";
  390. EXPECT_EQ(re.search(haystack.view(), result, PosixFlags::Multiline), true);
  391. EXPECT_EQ(result.count, 32u);
  392. EXPECT_EQ(result.matches.at(0).view.length(), 0u);
  393. EXPECT_EQ(result.matches.at(10).view.length(), 1u);
  394. EXPECT_EQ(result.matches.at(10).view, "a");
  395. EXPECT_EQ(result.matches.at(31).view.length(), 0u);
  396. }
  397. TEST_CASE(simple_period_end_benchmark)
  398. {
  399. Regex<PosixExtended> re("hello.$");
  400. RegexResult m;
  401. EXPECT_EQ(re.search("Hello1", m), false);
  402. EXPECT_EQ(re.search("hello1hello1", m), true);
  403. EXPECT_EQ(re.search("hello2hell", m), false);
  404. EXPECT_EQ(re.search("hello?", m), true);
  405. }
  406. TEST_CASE(ECMA262_parse)
  407. {
  408. struct _test {
  409. const char* pattern;
  410. regex::Error expected_error { regex::Error::NoError };
  411. };
  412. constexpr _test tests[] {
  413. { "^hello.$" },
  414. { "^(hello.)$" },
  415. { "^h{0,1}ello.$" },
  416. { "^hello\\W$" },
  417. { "^hell\\w.$" },
  418. { "^hell\\x6f1$" }, // ^hello1$
  419. { "^hel(?:l\\w).$" },
  420. { "^hel(?<LO>l\\w).$" },
  421. { "^[-a-zA-Z\\w\\s]+$" },
  422. { "\\bhello\\B" },
  423. { "^[\\w+/_-]+[=]{0,2}$" }, // #4189
  424. { "^(?:[^<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]*)$)" }, // #4189
  425. { "\\/" }, // #4189
  426. { ",/=-:" }, // #4243
  427. { "\\x" }, // Even invalid escapes are allowed if ~unicode.
  428. { "\\", regex::Error::InvalidTrailingEscape },
  429. { "(?", regex::Error::InvalidCaptureGroup },
  430. };
  431. for (auto& test : tests) {
  432. Regex<ECMA262> re(test.pattern);
  433. EXPECT_EQ(re.parser_result.error, test.expected_error);
  434. #ifdef REGEX_DEBUG
  435. dbg() << "\n";
  436. RegexDebug regex_dbg(stderr);
  437. regex_dbg.print_raw_bytecode(re);
  438. regex_dbg.print_header();
  439. regex_dbg.print_bytecode(re);
  440. dbg() << "\n";
  441. #endif
  442. }
  443. }
  444. TEST_CASE(ECMA262_match)
  445. {
  446. struct _test {
  447. const char* pattern;
  448. const char* subject;
  449. bool matches { true };
  450. ECMAScriptFlags options {};
  451. };
  452. constexpr _test tests[] {
  453. { "^hello.$", "hello1" },
  454. { "^(hello.)$", "hello1" },
  455. { "^h{0,1}ello.$", "ello1" },
  456. { "^hello\\W$", "hello!" },
  457. { "^hell\\w.$", "hellx!" },
  458. { "^hell\\x6f1$", "hello1" },
  459. { "^hel(?<LO>l.)1$", "hello1" },
  460. { "^hel(?<LO>l.)1*\\k<LO>.$", "hello1lo1" },
  461. { "^[-a-z1-3\\s]+$", "hell2 o1" },
  462. { .pattern = "\\bhello\\B", .subject = "hello1", .options = ECMAScriptFlags::Global },
  463. { "\\b.*\\b", "hello1" },
  464. { "[^\\D\\S]{2}", "1 " },
  465. { "bar(?=f.)foo", "barfoo" },
  466. { "bar(?=foo)bar", "barbar", false },
  467. { "bar(?!foo)bar", "barbar", true },
  468. { "bar(?!bar)bar", "barbar", false },
  469. { "bar.*(?<=foo)", "barbar", false },
  470. { "bar.*(?<!foo)", "barbar", true },
  471. { "((...)X)+", "fooXbarXbazX", true },
  472. { "(?:)", "", true },
  473. };
  474. for (auto& test : tests) {
  475. Regex<ECMA262> re(test.pattern, test.options);
  476. #ifdef REGEX_DEBUG
  477. dbg() << "\n";
  478. RegexDebug regex_dbg(stderr);
  479. regex_dbg.print_raw_bytecode(re);
  480. regex_dbg.print_header();
  481. regex_dbg.print_bytecode(re);
  482. dbg() << "\n";
  483. #endif
  484. EXPECT_EQ(re.parser_result.error, Error::NoError);
  485. EXPECT_EQ(re.match(test.subject).success, test.matches);
  486. }
  487. }
  488. TEST_MAIN(Regex)