Skip to content

Commit

Permalink
Unit test matchScalar and reversMatchScalar
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Hearst committed Jan 20, 2025
1 parent 2d3c691 commit f28e9fa
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 12 deletions.
8 changes: 5 additions & 3 deletions Sources/_StringProcessing/Engine/MEBuiltins.swift
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ extension String {
isStrictASCII: Bool,
isScalarSemantics: Bool
) -> String.Index? {
guard currentPosition >= start else { return nil }
guard currentPosition > start else { return nil }
if case .definite(let result) = _quickReverseMatchBuiltinCC(
cc,
at: currentPosition,
Expand All @@ -443,14 +443,15 @@ extension String {
isScalarSemantics: isScalarSemantics)
}

// TODO: JH - Is there any value in testing this? How would it be tested?
// Mentioned in ProgrammersManual.md, update docs if redesigned
@inline(__always)
private func _quickMatchBuiltinCC(
_ cc: _CharacterClassModel.Representation,
at currentPosition: String.Index,
limitedBy end: String.Index,
isInverted: Bool,
isStrictASCII: Bool,
isStrictASCII: Bool, // TODO: JH - Is this just reserved for future use? A relic of the past?
isScalarSemantics: Bool
) -> QuickResult<String.Index?> {
assert(currentPosition < end)
Expand All @@ -474,7 +475,7 @@ extension String {
isStrictASCII: Bool,
isScalarSemantics: Bool
) -> QuickResult<String.Index?> {
assert(currentPosition >= start)
assert(currentPosition > start)
guard let (previous, result) = _quickReverseMatch(
cc,
at: currentPosition,
Expand All @@ -486,6 +487,7 @@ extension String {
return .definite(result == isInverted ? nil : previous)
}

// TODO: JH - How can this be unit tested?
// Mentioned in ProgrammersManual.md, update docs if redesigned
@inline(never)
private func _thoroughMatchBuiltinCC(
Expand Down
5 changes: 2 additions & 3 deletions Sources/_StringProcessing/Engine/Processor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ extension Processor {
return true
}

// If `start` falls in the middle of a character, and we are trying to advance
// If `start` falls in the middle of a character, and we are trying to reverse
// by one "character", then we should max out at `start` even though the above
// reversal will result in `nil`.
if n == 1, let idx = input.unicodeScalars.index(
Expand Down Expand Up @@ -994,7 +994,7 @@ extension String {
) -> Index? {
// TODO: extremely quick-check-able
// TODO: can be sped up with string internals
guard pos >= start else { return nil }
guard pos > start else { return nil }
let curScalar = unicodeScalars[pos]

if isCaseInsensitive {
Expand All @@ -1006,7 +1006,6 @@ extension String {
guard curScalar == scalar else { return nil }
}

guard pos != start else { return pos }
let idx = unicodeScalars.index(before: pos)
assert(idx >= start, "Input is a substring with a sub-scalar startIndex.")

Expand Down
268 changes: 268 additions & 0 deletions Tests/MatchingEngineTests/MatchingEngineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,272 @@ final class StringMatchingTests: XCTestCase {
// Then we should get nil because there isn't an index before `startIndex`
XCTAssertNil(result)
}

func testMatchBuiltinCCAtEnd() {
// Given
let sut = ""

// When
let next = sut.matchBuiltinCC(
.any,
at: sut.endIndex,
limitedBy: sut.endIndex,
isInverted: false,
isStrictASCII: false,
isScalarSemantics: true
)

// Then
XCTAssertNil(next)
}
}

// MARK: matchScalar tests
extension StringMatchingTests {
func testMatchScalar() {
// Given
let sut = "bar"

// When
let next = sut.matchScalar(
"b",
at: sut.startIndex,
limitedBy: sut.endIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertEqual(next, sut.index(after: sut.startIndex))
}

func testMatchScalarNoMatch() {
// Given
let sut = "bar"

// When
let next = sut.matchScalar(
"a",
at: sut.startIndex,
limitedBy: sut.endIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertNil(next)
}

func testMatchScalarCaseInsensitive() {
// Given
let sut = "BAR"

// When
let next = sut.matchScalar(
"b",
at: sut.startIndex,
limitedBy: sut.endIndex,
boundaryCheck: false,
isCaseInsensitive: true
)

// Then
XCTAssertEqual(next, sut.index(after: sut.startIndex))
}

func testMatchScalarCaseInsensitiveNoMatch() {
// Given
let sut = "BAR"

// When
let next = sut.matchScalar(
"a",
at: sut.startIndex,
limitedBy: sut.endIndex,
boundaryCheck: false,
isCaseInsensitive: true
)

// Then
XCTAssertNil(next)
}

func testMatchScalarAtEnd() {
// Given
let sut = ""

// When
let next = sut.matchScalar(
"a",
at: sut.endIndex,
limitedBy: sut.endIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertNil(next)
}

func testMatchScalarBoundaryCheck() {
// Given
// \u{62}\u{300}\u{316}\u{65}\u{73}\u{74}
let sut = "b̖̀est"

// When
let next = sut.matchScalar(
"\u{300}",
at: sut.unicodeScalars.index(after: sut.unicodeScalars.startIndex),
limitedBy: sut.endIndex,
boundaryCheck: true,
isCaseInsensitive: false
)

// Then
XCTAssertNil(next)
}

func testMatchScalarNoBoundaryCheck() {
// Given
// \u{62}\u{300}\u{316}\u{65}\u{73}\u{74}
let sut = "b̖̀est"
let atPos = sut.unicodeScalars.index(after: sut.unicodeScalars.startIndex)

// When
let next = sut.matchScalar(
"\u{300}",
at: atPos,
limitedBy: sut.endIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertEqual(next, sut.unicodeScalars.index(after: atPos))
}
}

// MARK: reverseMatchScalar tests
extension StringMatchingTests {
func testReverseMatchScalar() {
// Given
let sut = "bar"

// When
let previous = sut.reverseMatchScalar(
"a",
at: sut.index(after: sut.startIndex),
limitedBy: sut.startIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertEqual(previous, sut.startIndex)
}

func testReverseMatchScalarNoMatch() {
// Given
let sut = "bar"

// When
let previous = sut.reverseMatchScalar(
"b",
at: sut.index(after: sut.startIndex),
limitedBy: sut.startIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertNil(previous)
}

func testReverseMatchScalarCaseInsensitive() {
// Given
let sut = "BAR"

// When
let previous = sut.reverseMatchScalar(
"a",
at: sut.index(after: sut.startIndex),
limitedBy: sut.startIndex,
boundaryCheck: false,
isCaseInsensitive: true
)

// Then
XCTAssertEqual(previous, sut.startIndex)
}

func testReverseMatchScalarCaseInsensitiveNoMatch() {
// Given
let sut = "BAR"

// When
let previous = sut.reverseMatchScalar(
"b",
at: sut.index(after: sut.startIndex),
limitedBy: sut.startIndex,
boundaryCheck: false,
isCaseInsensitive: true
)

// Then
XCTAssertNil(previous)
}

func testReverseMatchScalarAtStart() {
// Given
let sut = "a"

// When
let previous = sut.reverseMatchScalar(
"a",
at: sut.startIndex,
limitedBy: sut.startIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertNil(previous)
}

func testReverseMatchScalarBoundaryCheck() {
// Given
// \u{61}\u{62}\u{300}\u{316}\u{63}\u{64}
let sut = "ab̖̀cd"

// When
let previous = sut.reverseMatchScalar(
"\u{316}",
at: sut.unicodeScalars.index(sut.unicodeScalars.startIndex, offsetBy: 3),
limitedBy: sut.startIndex,
boundaryCheck: true,
isCaseInsensitive: false
)

// Then
XCTAssertNil(previous)
}

func testReverseMatchScalarNoBoundaryCheck() {
// Given
// \u{61}\u{62}\u{300}\u{316}\u{63}\u{64}
let sut = "ab̖̀cd"
let atPos = sut.unicodeScalars.index(sut.unicodeScalars.startIndex, offsetBy: 3)

// When
let previous = sut.reverseMatchScalar(
"\u{316}",
at: atPos,
limitedBy: sut.startIndex,
boundaryCheck: false,
isCaseInsensitive: false
)

// Then
XCTAssertEqual(previous, sut.unicodeScalars.index(before: atPos))
}
}
11 changes: 5 additions & 6 deletions Tests/RegexTests/MatchTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1637,12 +1637,11 @@ extension RegexTests {
("123defg", nil)
)

// FIXME: quickMatch and thoroughMatch have different results
// firstMatchTest(
// #"(?<=\d{1,3}-.{1,3}-\d{1,3})suffix"#,
// input: "123-_+/-789suffix",
// match: "suffix"
// )
firstMatchTest(
#"(?<=\d{1,3}-.{1,3}-\d{1,3})suffix"#,
input: "123-_+/-789suffix",
match: "suffix"
)

firstMatchTests(
#"(?<=^\d{1,3})abc"#,
Expand Down

0 comments on commit f28e9fa

Please sign in to comment.