@@ -434,7 +434,157 @@ public static IEnumerable<object[]> Matches_TestData()
434434 }
435435 }
436436
437- #if ! NETFRAMEWORK // these tests currently fail on .NET Framework, and we need to check IsDynamicCodeCompiled but that doesn't exist on .NET Framework
437+ if ( ! RegexHelpers . IsNonBacktracking ( engine ) ) // balancing groups aren't supported
438+ {
439+ // ExpressionConditional with balancing groups inside a loop, auto-numbered capture groups
440+
441+ // Balancing group conditional with auto-numbered capture group and dot
442+ yield return new object [ ]
443+ {
444+ engine , @"(?((?'-1'))|(.)+)+(?!(?'-1'))" , "abc" , RegexOptions . None , new [ ]
445+ {
446+ new CaptureData ( "a" , 0 , 1 ) ,
447+ new CaptureData ( "b" , 1 , 1 ) ,
448+ new CaptureData ( "c" , 2 , 1 ) ,
449+ }
450+ } ;
451+
452+ // Balancing group conditional with auto-numbered capture group and literal
453+ yield return new object [ ]
454+ {
455+ engine , @"(?((?'-1'))|(a)+)+(?!(?'-1'))" , "aaa" , RegexOptions . None , new [ ]
456+ {
457+ new CaptureData ( "a" , 0 , 1 ) ,
458+ new CaptureData ( "a" , 1 , 1 ) ,
459+ new CaptureData ( "a" , 2 , 1 ) ,
460+ }
461+ } ;
462+
463+ // Alternation in no-branch with empty second branch, no match expected
464+ yield return new object [ ]
465+ {
466+ engine , @"(?((?'-1'))|((?'1'.)+|()))+(?!(?'-1'))" , "a" , RegexOptions . None ,
467+ Array . Empty < CaptureData > ( )
468+ } ;
469+
470+ // Balancing group conditional with quantified pop {2}
471+ yield return new object [ ]
472+ {
473+ engine , @"(?((?'-1'){2})|((?'1'a)+))+(?!(?'-1'))" , "aa" , RegexOptions . None , new [ ]
474+ {
475+ new CaptureData ( "a" , 0 , 1 ) ,
476+ new CaptureData ( "a" , 1 , 1 ) ,
477+ }
478+ } ;
479+
480+ // ExpressionConditional with balancing groups inside a loop
481+
482+ // Balancing group conditional with alternation in no-branch, no match
483+ yield return new object [ ]
484+ {
485+ engine , @"(?((?'-1'))|((?'1'\S)+|(?'1'\s)))+(?!(?'-1'))" , "abc" , RegexOptions . None ,
486+ Array . Empty < CaptureData > ( )
487+ } ;
488+
489+ // Balancing group conditional with nested captures in alternation
490+ yield return new object [ ]
491+ {
492+ engine , @"(?((?'-1'){6})|((?'1'(?'2'\S))+|(?'1'(?'2'\s))))+(?!(?'-1'))" , "it not" , RegexOptions . None , new [ ]
493+ {
494+ new CaptureData ( "it " , 0 , 3 ) ,
495+ new CaptureData ( "not" , 3 , 3 ) ,
496+ }
497+ } ;
498+
499+ // Alternation in capturing group in no-branch, no match expected
500+ yield return new object [ ]
501+ {
502+ engine , @"(?((?'-1'))|((?'1'a)+|(?'1'b)))+(?!(?'-1'))" , "abc" , RegexOptions . None ,
503+ Array . Empty < CaptureData > ( )
504+ } ;
505+ yield return new object [ ]
506+ {
507+ engine , @"(?((?'-1'))|((?'1'a)+|(?'1'b)))+(?!(?'-1'))" , "aaa" , RegexOptions . None ,
508+ Array . Empty < CaptureData > ( )
509+ } ;
510+
511+ // No-branch with quantifier but no wrapping capture group
512+ yield return new object [ ]
513+ {
514+ engine , @"(?((?'-1'))|(?'1'\S)+)+(?!(?'-1'))" , "abc" , RegexOptions . None , new [ ]
515+ {
516+ new CaptureData ( "a" , 0 , 1 ) ,
517+ new CaptureData ( "b" , 1 , 1 ) ,
518+ new CaptureData ( "c" , 2 , 1 ) ,
519+ }
520+ } ;
521+ yield return new object [ ]
522+ {
523+ engine , @"(?((?'-1'))|(?'1'a)+)+(?!(?'-1'))" , "aaa" , RegexOptions . None , new [ ]
524+ {
525+ new CaptureData ( "a" , 0 , 1 ) ,
526+ new CaptureData ( "a" , 1 , 1 ) ,
527+ new CaptureData ( "a" , 2 , 1 ) ,
528+ }
529+ } ;
530+
531+ // No-branch with quantifier inside wrapping capture group
532+ yield return new object [ ]
533+ {
534+ engine , @"(?((?'-1'))|((?'1'\S)+))+(?!(?'-1'))" , "abc" , RegexOptions . None ,
535+ Array . Empty < CaptureData > ( )
536+ } ;
537+
538+ // Non-capturing group wrapping alternation in no-branch
539+ yield return new object [ ]
540+ {
541+ engine , @"(?((?'-1'))|(?:(?'1'a)+|(?'1'b)))+(?!(?'-1'))" , "aaa" , RegexOptions . None , new [ ]
542+ {
543+ new CaptureData ( "a" , 0 , 1 ) ,
544+ new CaptureData ( "a" , 1 , 1 ) ,
545+ new CaptureData ( "a" , 2 , 1 ) ,
546+ }
547+ } ;
548+ yield return new object [ ]
549+ {
550+ engine , @"(?((?'-1'))|(?:(?'1'a)+|(?'1'b)))+(?!(?'-1'))" , "abc" , RegexOptions . None , new [ ]
551+ {
552+ new CaptureData ( "a" , 0 , 1 ) ,
553+ new CaptureData ( "b" , 1 , 1 ) ,
554+ }
555+ } ;
556+
557+ // Balancing group conditional with single char in no-branch
558+ yield return new object [ ]
559+ {
560+ engine , @"(?((?'-1'))|(?'1'a))+(?!(?'-1'))" , "aaa" , RegexOptions . None , new [ ]
561+ {
562+ new CaptureData ( "a" , 0 , 1 ) ,
563+ new CaptureData ( "a" , 1 , 1 ) ,
564+ new CaptureData ( "a" , 2 , 1 ) ,
565+ }
566+ } ;
567+
568+ // Balancing group conditional with multi-word input
569+ yield return new object [ ]
570+ {
571+ engine , @"(?((?'-1'))|(?'1'\S)+)+(?!(?'-1'))" , "hello world" , RegexOptions . None , new [ ]
572+ {
573+ new CaptureData ( "h" , 0 , 1 ) ,
574+ new CaptureData ( "e" , 1 , 1 ) ,
575+ new CaptureData ( "l" , 2 , 1 ) ,
576+ new CaptureData ( "l" , 3 , 1 ) ,
577+ new CaptureData ( "o" , 4 , 1 ) ,
578+ new CaptureData ( "w" , 6 , 1 ) ,
579+ new CaptureData ( "o" , 7 , 1 ) ,
580+ new CaptureData ( "r" , 8 , 1 ) ,
581+ new CaptureData ( "l" , 9 , 1 ) ,
582+ new CaptureData ( "d" , 10 , 1 ) ,
583+ }
584+ } ;
585+ }
586+
587+ #if ! NETFRAMEWORK // these tests currently fail on .NET Framework
438588 yield return new object [ ]
439589 {
440590 engine , "@(a*)+?" , "@" , RegexOptions . None , new [ ]
0 commit comments