@@ -25,23 +25,33 @@ func _firstMatch(
25
25
input: String ,
26
26
validateOptimizations: Bool ,
27
27
syntax: SyntaxOptions = . traditional
28
- ) throws -> ( String , [ String ? ] ) {
28
+ ) throws -> ( String , [ String ? ] ) ? {
29
29
var regex = try Regex ( regexStr, syntax: syntax)
30
- guard let result = try regex. firstMatch ( in: input) else {
31
- throw MatchError ( " match not found for \( regexStr) in \( input) " )
32
- }
33
- let caps = result. output. slices ( from: input)
34
-
30
+ let result = try regex. firstMatch ( in: input)
31
+
35
32
if validateOptimizations {
36
33
regex. _setCompilerOptionsForTesting ( . disableOptimizations)
37
- guard let unoptResult = try regex. firstMatch ( in: input) else {
34
+ let unoptResult = try regex. firstMatch ( in: input)
35
+ if result != nil && unoptResult == nil {
38
36
throw MatchError ( " match not found for unoptimized \( regexStr) in \( input) " )
39
37
}
40
- XCTAssertEqual (
41
- String ( input [ result. range] ) ,
42
- String ( input [ unoptResult. range] ) ,
43
- " Unoptimized regex returned a different result " )
38
+ if result == nil && unoptResult != nil {
39
+ throw MatchError ( " match not found in optimized \( regexStr) in \( input) " )
40
+ }
41
+ if let result = result, let unoptResult = unoptResult {
42
+ let optMatch = String ( input [ result. range] )
43
+ let unoptMatch = String ( input [ unoptResult. range] )
44
+ if optMatch != unoptMatch {
45
+ throw MatchError ( """
46
+
47
+ Unoptimized regex returned: ' \( unoptMatch) '
48
+ Optimized regex returned: ' \( optMatch) '
49
+ """ )
50
+ }
51
+ }
44
52
}
53
+ guard let result = result else { return nil }
54
+ let caps = result. output. slices ( from: input)
45
55
return ( String ( input [ result. range] ) , caps. map { $0. map ( String . init) } )
46
56
}
47
57
@@ -147,21 +157,19 @@ func firstMatchTest(
147
157
line: UInt = #line
148
158
) {
149
159
do {
150
- let ( found, _ ) = try _firstMatch (
160
+ let found = try _firstMatch (
151
161
regex,
152
162
input: input,
153
163
validateOptimizations: validateOptimizations,
154
- syntax: syntax)
164
+ syntax: syntax) ? . 0
155
165
156
166
if xfail {
157
167
XCTAssertNotEqual ( found, match, file: file, line: line)
158
168
} else {
159
169
XCTAssertEqual ( found, match, file: file, line: line)
160
170
}
161
171
} catch {
162
- // FIXME: This allows non-matches to succeed even when xfail'd
163
- // When xfail == true, this should report failure for match == nil
164
- if !xfail && match != nil {
172
+ if !xfail {
165
173
XCTFail ( " \( error) " , file: file, line: line)
166
174
}
167
175
return
@@ -421,8 +429,7 @@ extension RegexTests {
421
429
" a++a " ,
422
430
( " babc " , nil ) ,
423
431
( " baaabc " , nil ) ,
424
- ( " bb " , nil ) ,
425
- xfail: true )
432
+ ( " bb " , nil ) )
426
433
firstMatchTests (
427
434
" a+?a " ,
428
435
( " babc " , nil ) ,
@@ -498,23 +505,19 @@ extension RegexTests {
498
505
( " baabc " , nil ) ,
499
506
( " bb " , nil ) )
500
507
501
- // XFAIL'd versions of the above
502
508
firstMatchTests (
503
509
" a{2,4}+a " ,
504
- ( " baaabc " , nil ) ,
505
- xfail: true )
510
+ ( " baaabc " , nil ) )
506
511
firstMatchTests (
507
512
" a{,4}+a " ,
508
513
( " babc " , nil ) ,
509
514
( " baabc " , nil ) ,
510
- ( " baaabc " , nil ) ,
511
- xfail: true )
515
+ ( " baaabc " , nil ) )
512
516
firstMatchTests (
513
517
" a{2,}+a " ,
514
518
( " baaabc " , nil ) ,
515
519
( " baaaaabc " , nil ) ,
516
- ( " baaaaaaaabc " , nil ) ,
517
- xfail: true )
520
+ ( " baaaaaaaabc " , nil ) )
518
521
519
522
// XFAIL'd possessive tests
520
523
firstMatchTests (
@@ -709,6 +712,11 @@ extension RegexTests {
709
712
}
710
713
firstMatchTest ( #"[\t-\t]"# , input: " \u{8} \u{A} \u{9} " , match: " \u{9} " )
711
714
715
+ // FIXME: This produces a different result with and without optimizations.
716
+ firstMatchTest ( #"[1-2]"# , input: " 1️⃣ " , match: nil , xfail: true )
717
+ firstMatchTest ( #"[1-2]"# , input: " 1️⃣ " , match: nil ,
718
+ validateOptimizations: false )
719
+
712
720
// Currently not supported in the matching engine.
713
721
for c : UnicodeScalar in [ " a " , " b " , " c " ] {
714
722
firstMatchTest ( #"[\c!-\C-#]"# , input: " def \( c) " , match: " \( c) " ,
@@ -1054,8 +1062,8 @@ extension RegexTests {
1054
1062
// TODO: Oniguruma \y and \Y
1055
1063
firstMatchTests (
1056
1064
#"\u{65}"# , // Scalar 'e' is present in both
1057
- ( " Cafe \u{301} " , nil ) , // but scalar mode requires boundary at end of match
1058
- xfail : true )
1065
+ ( " Cafe \u{301} " , nil ) ) // but scalar mode requires boundary at end of match
1066
+
1059
1067
firstMatchTests (
1060
1068
#"\u{65}"# , // Scalar 'e' is present in both
1061
1069
( " Sol Cafe " , " e " ) ) // standalone is okay
@@ -1647,19 +1655,15 @@ extension RegexTests {
1647
1655
firstMatchTest ( #"\u{65 301}$"# , input: eComposed, match: eComposed)
1648
1656
1649
1657
// FIXME: Implicit \y at end of match
1650
- firstMatchTest ( #"\u{65}"# , input: eDecomposed, match: nil ,
1651
- xfail: true )
1658
+ firstMatchTest ( #"\u{65}"# , input: eDecomposed, match: nil )
1652
1659
firstMatchTest ( #"\u{65}$"# , input: eDecomposed, match: nil )
1653
- // FIXME: \y is unsupported
1654
- firstMatchTest ( #"\u{65}\y"# , input: eDecomposed, match: nil ,
1655
- xfail: true )
1660
+ firstMatchTest ( #"\u{65}\y"# , input: eDecomposed, match: nil )
1656
1661
1657
1662
// FIXME: Unicode scalars are only matched at the start of a grapheme cluster
1658
1663
firstMatchTest ( #"\u{301}"# , input: eDecomposed, match: " \u{301} " ,
1659
1664
xfail: true )
1660
- // FIXME: \y is unsupported
1661
- firstMatchTest ( #"\y\u{301}"# , input: eDecomposed, match: nil ,
1662
- xfail: true )
1665
+
1666
+ firstMatchTest ( #"\y\u{301}"# , input: eDecomposed, match: nil )
1663
1667
}
1664
1668
1665
1669
func testCanonicalEquivalence( ) throws {
@@ -1717,13 +1721,11 @@ extension RegexTests {
1717
1721
// \s
1718
1722
firstMatchTest ( #"\s"# , input: " " , match: " " )
1719
1723
// FIXME: \s shouldn't match a number composed with a non-number character
1720
- firstMatchTest ( #"\s\u{305}"# , input: " " , match: nil ,
1721
- xfail: true )
1724
+ firstMatchTest ( #"\s\u{305}"# , input: " " , match: nil )
1722
1725
// \p{Whitespace}
1723
1726
firstMatchTest ( #"\s"# , input: " " , match: " " )
1724
- // FIXME: \p{Whitespace} shouldn't match whitespace composed with a non-whitespace character
1725
- firstMatchTest ( #"\s\u{305}"# , input: " " , match: nil ,
1726
- xfail: true )
1727
+ // \p{Whitespace} shouldn't match whitespace composed with a non-whitespace character
1728
+ firstMatchTest ( #"\s\u{305}"# , input: " " , match: nil )
1727
1729
}
1728
1730
1729
1731
func testCanonicalEquivalenceCustomCharacterClass( ) throws {
0 commit comments