@@ -1031,7 +1031,6 @@ void test_gh_5165_grep() {
1031
1031
middle_nl_with_caret.should_search_fail (" ^a" );
1032
1032
middle_nl_with_caret.should_search_fail (" ca" );
1033
1033
middle_nl_with_caret.should_search_fail (" ^b" );
1034
- middle_nl_with_caret.should_search_fail (" ca" );
1035
1034
middle_nl_with_caret.should_search_fail (" cb" );
1036
1035
}
1037
1036
{
@@ -1171,6 +1170,196 @@ void test_gh_5253() {
1171
1170
g_regexTester.should_not_match (" a" , " ()*" );
1172
1171
}
1173
1172
1173
+ void test_gh_5362_syntax_option (const syntax_option_type basic_or_grep) {
1174
+ {
1175
+ const test_regex ending_anchor (&g_regexTester, " meo[wW]$" , basic_or_grep);
1176
+ ending_anchor.should_search_match (" kitten_meow" , " meow" );
1177
+ ending_anchor.should_search_fail (" homeowner" );
1178
+ }
1179
+ {
1180
+ const test_regex middle_anchor (&g_regexTester, " me$o[wW]" , basic_or_grep);
1181
+ middle_anchor.should_search_fail (" kitten_meow" );
1182
+ middle_anchor.should_search_fail (" homeowner" );
1183
+ middle_anchor.should_search_match (" home$owner" , " me$ow" );
1184
+ }
1185
+ {
1186
+ const test_regex double_dollars (&g_regexTester, " meo[wW]$$" , basic_or_grep);
1187
+ double_dollars.should_search_fail (" kitten_meow" );
1188
+ double_dollars.should_search_fail (" homeowner" );
1189
+ double_dollars.should_search_match (" kitten_meow$" , " meow$" );
1190
+ double_dollars.should_search_fail (" kitten_meow$$" );
1191
+ double_dollars.should_search_fail (" homeow$ner" );
1192
+ double_dollars.should_search_fail (" homeow$$ner" );
1193
+ }
1194
+
1195
+ g_regexTester.should_not_match (" me$ow" , R"( \(me$\)o[wW])" , basic_or_grep);
1196
+ g_regexTester.should_not_match (" meow" , R"( \(me$\)o[wW])" , basic_or_grep);
1197
+
1198
+ {
1199
+ const test_regex singlegroup_anchor (&g_regexTester, R"( \(meo[wW]$\))" , basic_or_grep);
1200
+ singlegroup_anchor.should_search_match (" kitten_meow" , " meow" );
1201
+ singlegroup_anchor.should_search_fail (" kitten_meow$" );
1202
+ singlegroup_anchor.should_search_fail (" homeowner" );
1203
+ singlegroup_anchor.should_search_fail (" homeow$ner" );
1204
+ }
1205
+ {
1206
+ const test_regex suffixedgroup_anchor (&g_regexTester, R"( \(meo[wW]$\).*)" , basic_or_grep);
1207
+ suffixedgroup_anchor.should_search_match (" kitten_meow" , " meow" );
1208
+ suffixedgroup_anchor.should_search_fail (" kitten_meow$" );
1209
+ suffixedgroup_anchor.should_search_fail (" homeowner" );
1210
+ suffixedgroup_anchor.should_search_fail (" homeow$ner" );
1211
+ }
1212
+ {
1213
+ const test_regex firstgroup_anchor (&g_regexTester, R"( \(meo[wW]$\)\(.*\))" , basic_or_grep);
1214
+ firstgroup_anchor.should_search_match (" kitten_meow" , " meow" );
1215
+ firstgroup_anchor.should_search_fail (" kitten_meow$" );
1216
+ firstgroup_anchor.should_search_fail (" homeowner" );
1217
+ firstgroup_anchor.should_search_fail (" homeow$ner" );
1218
+ }
1219
+ {
1220
+ const test_regex nested_anchor (&g_regexTester, R"( \(\(meo[wW]$\)$\).*)" , basic_or_grep);
1221
+ nested_anchor.should_search_match (" kitten_meow" , " meow" );
1222
+ nested_anchor.should_search_fail (" kitten_meow$" );
1223
+ nested_anchor.should_search_fail (" kitten_meow$$" );
1224
+ nested_anchor.should_search_fail (" homeowner" );
1225
+ nested_anchor.should_search_fail (" homeow$ner" );
1226
+ nested_anchor.should_search_fail (" homeow$$ner" );
1227
+ }
1228
+ {
1229
+ const test_regex double_dollars (&g_regexTester, R"( \(meo[wW]$$\).*)" , basic_or_grep);
1230
+ double_dollars.should_search_fail (" kitten_meow" );
1231
+ double_dollars.should_search_match (" kitten_meow$" , " meow$" );
1232
+ double_dollars.should_search_fail (" kitten_meow$$" );
1233
+ double_dollars.should_search_fail (" homeowner" );
1234
+ double_dollars.should_search_fail (" homeow$ner" );
1235
+ double_dollars.should_search_fail (" homeow$$ner" );
1236
+ }
1237
+
1238
+ // Validate that there is no special behavior near bars,
1239
+ // as they are alternation operators in regex modes other than basic or grep.
1240
+ {
1241
+ const test_regex middle_bar (&g_regexTester, " a|a$" , basic_or_grep);
1242
+ middle_bar.should_search_match (" a|a" , " a|a" );
1243
+ middle_bar.should_search_fail (" a|a$" );
1244
+ middle_bar.should_search_fail (" a|ab" );
1245
+ middle_bar.should_search_fail (" a" );
1246
+ }
1247
+ {
1248
+ const test_regex group_middle_bar (&g_regexTester, R"( \(a|a\)$)" , basic_or_grep);
1249
+ group_middle_bar.should_search_match (" a|a" , " a|a" );
1250
+ group_middle_bar.should_search_fail (" a|a$" );
1251
+ group_middle_bar.should_search_fail (" a|ab" );
1252
+ group_middle_bar.should_search_fail (" a" );
1253
+ }
1254
+ {
1255
+ const test_regex middle_bar_with_dollar (&g_regexTester, " a$|b$" , basic_or_grep);
1256
+ middle_bar_with_dollar.should_search_match (" a$|b" , " a$|b" );
1257
+ middle_bar_with_dollar.should_search_fail (" a|b" );
1258
+ middle_bar_with_dollar.should_search_fail (" a$|b$" );
1259
+ middle_bar_with_dollar.should_search_fail (" a$|bc" );
1260
+ middle_bar_with_dollar.should_search_fail (" a" );
1261
+ middle_bar_with_dollar.should_search_fail (" b" );
1262
+ }
1263
+ {
1264
+ const test_regex group_middle_bar_with_dollar (&g_regexTester, R"( \(a$|b\)$)" , basic_or_grep);
1265
+ group_middle_bar_with_dollar.should_search_match (" a$|b" , " a$|b" );
1266
+ group_middle_bar_with_dollar.should_search_fail (" a|b" );
1267
+ group_middle_bar_with_dollar.should_search_fail (" a$|b$" );
1268
+ group_middle_bar_with_dollar.should_search_fail (" a$|bc" );
1269
+ group_middle_bar_with_dollar.should_search_fail (" a" );
1270
+ group_middle_bar_with_dollar.should_search_fail (" b" );
1271
+ }
1272
+ }
1273
+
1274
+ void test_gh_5362_basic () {
1275
+ // test cases specific for basic regular expressions
1276
+ {
1277
+ const test_regex middle_nl (&g_regexTester, " a\n a$" , basic);
1278
+ middle_nl.should_search_match (" a\n a" , " a\n a" );
1279
+ middle_nl.should_search_fail (" a\n a$" );
1280
+ middle_nl.should_search_fail (" a\n ab" );
1281
+ middle_nl.should_search_fail (" a" );
1282
+ }
1283
+ {
1284
+ const test_regex group_middle_nl (&g_regexTester, " \\ (a\n a\\ )$" , basic);
1285
+ group_middle_nl.should_search_match (" a\n a" , " a\n a" );
1286
+ group_middle_nl.should_search_fail (" a\n a$" );
1287
+ group_middle_nl.should_search_fail (" a\n ab" );
1288
+ group_middle_nl.should_search_fail (" a" );
1289
+ }
1290
+ {
1291
+ const test_regex middle_nl_with_dollar (&g_regexTester, " a$\n b$" , basic);
1292
+ middle_nl_with_dollar.should_search_match (" a$\n b" , " a$\n b" );
1293
+ middle_nl_with_dollar.should_search_fail (" a\n b" );
1294
+ middle_nl_with_dollar.should_search_fail (" a$\n b$" );
1295
+ middle_nl_with_dollar.should_search_fail (" a$\n bc" );
1296
+ middle_nl_with_dollar.should_search_fail (" a" );
1297
+ middle_nl_with_dollar.should_search_fail (" b" );
1298
+ }
1299
+ {
1300
+ const test_regex group_middle_nl_with_dollar (&g_regexTester, " \\ (a$\n b\\ )$" , basic);
1301
+ group_middle_nl_with_dollar.should_search_match (" a$\n b" , " a$\n b" );
1302
+ group_middle_nl_with_dollar.should_search_fail (" a\n b" );
1303
+ group_middle_nl_with_dollar.should_search_fail (" a$\n b$" );
1304
+ group_middle_nl_with_dollar.should_search_fail (" a$\n bc" );
1305
+ group_middle_nl_with_dollar.should_search_fail (" a" );
1306
+ group_middle_nl_with_dollar.should_search_fail (" b" );
1307
+ }
1308
+ }
1309
+
1310
+ void test_gh_5362_grep () {
1311
+ // test cases specific for grep mode
1312
+ {
1313
+ const test_regex middle_nl (&g_regexTester, " a\n a$" , grep);
1314
+ middle_nl.should_search_match (" a\n a$" , " a" );
1315
+ middle_nl.should_search_match (" a\n ab" , " a" );
1316
+ middle_nl.should_search_match (" a" , " a" );
1317
+ middle_nl.should_search_fail (" b" );
1318
+ }
1319
+ {
1320
+ // This regular expression is not accepted by POSIX grep, but currently the regex parser does not reject it.
1321
+ // If the parser is changed to reject it, adjust this test case.
1322
+ const test_regex group_middle_nl (&g_regexTester, " \\ (a\n a\\ )$" , grep);
1323
+ group_middle_nl.should_search_match (" a\n a" , " a\n a" );
1324
+ group_middle_nl.should_search_fail (" a\n a$" );
1325
+ group_middle_nl.should_search_fail (" a\n ac" );
1326
+ group_middle_nl.should_search_fail (" a" );
1327
+ }
1328
+ {
1329
+ const test_regex middle_nl_with_dollar (&g_regexTester, " a$\n b$" , grep);
1330
+ middle_nl_with_dollar.should_search_match (" a$\n b" , " b" );
1331
+ middle_nl_with_dollar.should_search_match (" a\n b" , " a" );
1332
+ middle_nl_with_dollar.should_search_match (" ba" , " a" );
1333
+ middle_nl_with_dollar.should_search_match (" a" , " a" );
1334
+ middle_nl_with_dollar.should_search_match (" b" , " b" );
1335
+ middle_nl_with_dollar.should_search_match (" ab" , " b" );
1336
+ middle_nl_with_dollar.should_search_fail (" a$" );
1337
+ middle_nl_with_dollar.should_search_fail (" ac" );
1338
+ middle_nl_with_dollar.should_search_fail (" b$" );
1339
+ middle_nl_with_dollar.should_search_fail (" bc" );
1340
+ }
1341
+ {
1342
+ // This regular expression is not accepted by POSIX grep, but currently the regex parser does not reject it.
1343
+ // If the parser is changed to reject it, adjust this test case.
1344
+ const test_regex group_middle_nl_with_dollar (&g_regexTester, " \\ (a$\n b\\ )$" , grep);
1345
+ group_middle_nl_with_dollar.should_search_match (" a$\n b" , " a$\n b" );
1346
+ group_middle_nl_with_dollar.should_search_fail (" a\n b" );
1347
+ group_middle_nl_with_dollar.should_search_fail (" a$\n b$" );
1348
+ group_middle_nl_with_dollar.should_search_fail (" a$\n bc" );
1349
+ group_middle_nl_with_dollar.should_search_fail (" a" );
1350
+ group_middle_nl_with_dollar.should_search_fail (" b" );
1351
+ }
1352
+ }
1353
+
1354
+ void test_gh_5362 () {
1355
+ // GH-5362: `<regex>`: Properly parse dollar anchors in basic and grep mode
1356
+ test_gh_5362_syntax_option (basic);
1357
+ test_gh_5362_syntax_option (grep);
1358
+
1359
+ test_gh_5362_basic ();
1360
+ test_gh_5362_grep ();
1361
+ }
1362
+
1174
1363
int main () {
1175
1364
test_dev10_449367_case_insensitivity_should_work ();
1176
1365
test_dev11_462743_regex_collate_should_not_disable_regex_icase ();
@@ -1208,6 +1397,7 @@ int main() {
1208
1397
test_gh_5192 ();
1209
1398
test_gh_5214 ();
1210
1399
test_gh_5253 ();
1400
+ test_gh_5362 ();
1211
1401
1212
1402
return g_regexTester.result ();
1213
1403
}
0 commit comments