@@ -572,6 +572,44 @@ class AlgorithmTests: XCTestCase {
572572 s2. matches ( of: try Regex ( " a*? " ) ) . map { s2. offsets ( of: $0. range) } , [ 0 ..< 0 , 1 ..< 1 , 2 ..< 2 ] )
573573 XCTAssertEqual (
574574 s2. ranges ( of: try Regex ( " a*? " ) ) . map ( s2. offsets ( of: ) ) , [ 0 ..< 0 , 1 ..< 1 , 2 ..< 2 ] )
575+
576+ func checkContains(
577+ _ expected: Bool ,
578+ _ a: some StringProtocol ,
579+ _ b: some StringProtocol ,
580+ file: StaticString = #file, line: UInt = #line
581+ ) {
582+ let result = a. firstRange ( of: b) != nil
583+ XCTAssertEqual ( expected, result, file: file, line: line)
584+ }
585+
586+ // Make sure that searching doesn't match over a substring boundary, even
587+ // when the boundary is in the middle of a character.
588+ let cafe = " c \u{302} afe \u{301} "
589+ let cafeStringDropLastScalar = " c \u{302} afe "
590+ let cafeStringDropFirstScalar = " \u{302} afe \u{301} "
591+ let cafeSubDropLastScalar =
592+ cafe [ ..< ( cafe. unicodeScalars. index ( before: cafe. endIndex) ) ]
593+ let cafeSubDropFirstScalar =
594+ cafe [ cafe. unicodeScalars. index ( after: cafe. startIndex) ... ]
595+
596+ checkContains ( false , cafe, cafeStringDropLastScalar)
597+ checkContains ( false , cafe, cafeStringDropFirstScalar)
598+ checkContains ( false , cafe, cafeSubDropLastScalar)
599+ checkContains ( false , cafe, cafeSubDropFirstScalar)
600+ checkContains ( false , cafe, " afe " )
601+ checkContains ( true , cafe, " afé " )
602+ checkContains ( true , cafe, " ĉaf " )
603+
604+ checkContains ( false , cafeSubDropLastScalar, " afe \u{301} " )
605+ checkContains ( false , cafeSubDropLastScalar, " afé " )
606+ checkContains ( true , cafeSubDropLastScalar, " afe " )
607+ checkContains ( true , cafeSubDropLastScalar, cafeStringDropLastScalar)
608+
609+ checkContains ( false , cafeSubDropFirstScalar, " c \u{302} af " )
610+ checkContains ( false , cafeSubDropFirstScalar, " ĉaf " )
611+ checkContains ( true , cafeSubDropFirstScalar, " \u{302} af " )
612+ checkContains ( true , cafeSubDropFirstScalar, cafeStringDropFirstScalar)
575613 }
576614
577615 func testUnicodeScalarSemantics( ) throws {
0 commit comments