@@ -25,23 +25,33 @@ func _firstMatch(
2525 input: String ,
2626 validateOptimizations: Bool ,
2727 syntax: SyntaxOptions = . traditional
28- ) throws -> ( String , [ String ? ] ) {
28+ ) throws -> ( String , [ String ? ] ) ? {
2929 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+
3532 if validateOptimizations {
3633 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 {
3836 throw MatchError ( " match not found for unoptimized \( regexStr) in \( input) " )
3937 }
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+ }
4452 }
53+ guard let result = result else { return nil }
54+ let caps = result. output. slices ( from: input)
4555 return ( String ( input [ result. range] ) , caps. map { $0. map ( String . init) } )
4656}
4757
@@ -147,21 +157,19 @@ func firstMatchTest(
147157 line: UInt = #line
148158) {
149159 do {
150- let ( found, _ ) = try _firstMatch (
160+ let found = try _firstMatch (
151161 regex,
152162 input: input,
153163 validateOptimizations: validateOptimizations,
154- syntax: syntax)
164+ syntax: syntax) ? . 0
155165
156166 if xfail {
157167 XCTAssertNotEqual ( found, match, file: file, line: line)
158168 } else {
159169 XCTAssertEqual ( found, match, file: file, line: line)
160170 }
161171 } 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 {
165173 XCTFail ( " \( error) " , file: file, line: line)
166174 }
167175 return
@@ -421,8 +429,7 @@ extension RegexTests {
421429 " a++a " ,
422430 ( " babc " , nil ) ,
423431 ( " baaabc " , nil ) ,
424- ( " bb " , nil ) ,
425- xfail: true )
432+ ( " bb " , nil ) )
426433 firstMatchTests (
427434 " a+?a " ,
428435 ( " babc " , nil ) ,
@@ -498,23 +505,19 @@ extension RegexTests {
498505 ( " baabc " , nil ) ,
499506 ( " bb " , nil ) )
500507
501- // XFAIL'd versions of the above
502508 firstMatchTests (
503509 " a{2,4}+a " ,
504- ( " baaabc " , nil ) ,
505- xfail: true )
510+ ( " baaabc " , nil ) )
506511 firstMatchTests (
507512 " a{,4}+a " ,
508513 ( " babc " , nil ) ,
509514 ( " baabc " , nil ) ,
510- ( " baaabc " , nil ) ,
511- xfail: true )
515+ ( " baaabc " , nil ) )
512516 firstMatchTests (
513517 " a{2,}+a " ,
514518 ( " baaabc " , nil ) ,
515519 ( " baaaaabc " , nil ) ,
516- ( " baaaaaaaabc " , nil ) ,
517- xfail: true )
520+ ( " baaaaaaaabc " , nil ) )
518521
519522 // XFAIL'd possessive tests
520523 firstMatchTests (
@@ -709,6 +712,11 @@ extension RegexTests {
709712 }
710713 firstMatchTest ( #"[\t-\t]"# , input: " \u{8} \u{A} \u{9} " , match: " \u{9} " )
711714
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+
712720 // Currently not supported in the matching engine.
713721 for c : UnicodeScalar in [ " a " , " b " , " c " ] {
714722 firstMatchTest ( #"[\c!-\C-#]"# , input: " def \( c) " , match: " \( c) " ,
@@ -1054,8 +1062,8 @@ extension RegexTests {
10541062 // TODO: Oniguruma \y and \Y
10551063 firstMatchTests (
10561064 #"\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+
10591067 firstMatchTests (
10601068 #"\u{65}"# , // Scalar 'e' is present in both
10611069 ( " Sol Cafe " , " e " ) ) // standalone is okay
@@ -1647,19 +1655,15 @@ extension RegexTests {
16471655 firstMatchTest ( #"\u{65 301}$"# , input: eComposed, match: eComposed)
16481656
16491657 // 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 )
16521659 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 )
16561661
16571662 // FIXME: Unicode scalars are only matched at the start of a grapheme cluster
16581663 firstMatchTest ( #"\u{301}"# , input: eDecomposed, match: " \u{301} " ,
16591664 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 )
16631667 }
16641668
16651669 func testCanonicalEquivalence( ) throws {
@@ -1717,13 +1721,11 @@ extension RegexTests {
17171721 // \s
17181722 firstMatchTest ( #"\s"# , input: " " , match: " " )
17191723 // 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 )
17221725 // \p{Whitespace}
17231726 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 )
17271729 }
17281730
17291731 func testCanonicalEquivalenceCustomCharacterClass( ) throws {
0 commit comments