Skip to content

Commit 5b1490a

Browse files
committed
Increase algorithms test coverage
1 parent 4f8f67a commit 5b1490a

File tree

1 file changed

+118
-12
lines changed

1 file changed

+118
-12
lines changed

Tests/RegexTests/AlgorithmsTests.swift

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,30 @@ func makeSingleUseSequence<T>(element: T, count: Int) -> UnfoldSequence<T, Void>
3232
}
3333
}
3434

35+
struct CountedOptionSet: OptionSet {
36+
static var arrayLiteralCreationCount = 0
37+
38+
var rawValue: Int
39+
40+
static var one = Self(rawValue: 1)
41+
static var two = Self(rawValue: 1)
42+
}
43+
44+
extension CountedOptionSet {
45+
init(arrayLiteral: Self...) {
46+
Self.arrayLiteralCreationCount += 1
47+
self.rawValue = 0
48+
for element in arrayLiteral {
49+
self.insert(element)
50+
}
51+
}
52+
}
53+
3554
class AlgorithmTests: XCTestCase {
3655
func testContains() {
56+
XCTAssertTrue("abcde".contains("a"))
57+
XCTAssertTrue("abcde".contains("e" as Character))
58+
3759
XCTAssertTrue("".contains(""))
3860
XCTAssertTrue("abcde".contains(""))
3961
XCTAssertTrue("abcde".contains("abcd"))
@@ -51,7 +73,25 @@ class AlgorithmTests: XCTestCase {
5173
}
5274
}
5375

54-
func testRanges() {
76+
func testContainsSourceCompatibility() {
77+
CountedOptionSet.arrayLiteralCreationCount = 0
78+
79+
let both: CountedOptionSet = [.one, .two]
80+
let none: CountedOptionSet = []
81+
XCTAssertEqual(CountedOptionSet.arrayLiteralCreationCount, 2)
82+
83+
let cosArray = [both, .one, .two]
84+
XCTAssertFalse(cosArray.contains(none))
85+
86+
// This tests that `contains([])` uses the element-based `contains(_:)`
87+
// method, interpreting `[]` as an instance of `CountedOptionSet`, rather
88+
// than the collection-based overload, which would interpret `[]` as an
89+
// `Array<CountedOptionSet>`.
90+
XCTAssertFalse(cosArray.contains([]))
91+
XCTAssertEqual(CountedOptionSet.arrayLiteralCreationCount, 3)
92+
}
93+
94+
func testRegexRanges() {
5595
func expectRanges(
5696
_ string: String,
5797
_ regex: String,
@@ -78,6 +118,7 @@ class AlgorithmTests: XCTestCase {
78118
expectRanges("", "x", [])
79119
expectRanges("", "x+", [])
80120
expectRanges("", "x*", [0..<0])
121+
expectRanges("aaa", "a*", [0..<3, 3..<3])
81122
expectRanges("abc", "", [0..<0, 1..<1, 2..<2, 3..<3])
82123
expectRanges("abc", "x", [])
83124
expectRanges("abc", "x+", [])
@@ -92,8 +133,10 @@ class AlgorithmTests: XCTestCase {
92133
expectRanges("abc", "(a|b)*", [0..<2, 2..<2, 3..<3])
93134
expectRanges("abc", "(b|c)+", [1..<3])
94135
expectRanges("abc", "(b|c)*", [0..<0, 1..<3, 3..<3])
95-
96-
func expectStringRanges(
136+
}
137+
138+
func testStringRanges() {
139+
func expectRanges(
97140
_ input: String,
98141
_ pattern: String,
99142
_ expected: [Range<Int>],
@@ -110,16 +153,16 @@ class AlgorithmTests: XCTestCase {
110153
XCTAssertEqual(firstRange, expected.first, file: file, line: line)
111154
}
112155

113-
expectStringRanges("", "", [0..<0])
114-
expectStringRanges("abcde", "", [0..<0, 1..<1, 2..<2, 3..<3, 4..<4, 5..<5])
115-
expectStringRanges("abcde", "abcd", [0..<4])
116-
expectStringRanges("abcde", "bcde", [1..<5])
117-
expectStringRanges("abcde", "bcd", [1..<4])
118-
expectStringRanges("ababacabababa", "abababa", [6..<13])
119-
expectStringRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13])
156+
expectRanges("", "", [0..<0])
157+
expectRanges("abcde", "", [0..<0, 1..<1, 2..<2, 3..<3, 4..<4, 5..<5])
158+
expectRanges("abcde", "abcd", [0..<4])
159+
expectRanges("abcde", "bcde", [1..<5])
160+
expectRanges("abcde", "bcd", [1..<4])
161+
expectRanges("ababacabababa", "abababa", [6..<13])
162+
expectRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13])
120163
}
121164

122-
func testSplit() {
165+
func testRegexSplit() {
123166
func expectSplit(
124167
_ string: String,
125168
_ regex: String,
@@ -138,6 +181,26 @@ class AlgorithmTests: XCTestCase {
138181
expectSplit("a", "a", ["", ""])
139182
expectSplit("a____a____a", "_+", ["a", "a", "a"])
140183
expectSplit("____a____a____a____", "_+", ["", "a", "a", "a", ""])
184+
}
185+
186+
func testStringSplit() {
187+
func expectSplit(
188+
_ string: String,
189+
_ separator: String,
190+
_ expected: [Substring],
191+
file: StaticString = #file, line: UInt = #line
192+
) {
193+
let actual = Array(string.split(separator: separator, omittingEmptySubsequences: false))
194+
XCTAssertEqual(actual, expected, file: file, line: line)
195+
}
196+
197+
expectSplit("", "", [""])
198+
expectSplit("", "x", [""])
199+
expectSplit("a", "", ["", "a", ""])
200+
expectSplit("a", "x", ["a"])
201+
expectSplit("a", "a", ["", ""])
202+
expectSplit("a__a__a", "_", ["a", "", "a", "", "a"])
203+
expectSplit("_a_a_a_", "_", ["", "a", "a", "a", ""])
141204

142205
XCTAssertEqual("".split(separator: ""), [])
143206
XCTAssertEqual("".split(separator: "", omittingEmptySubsequences: false), [""])
@@ -149,6 +212,24 @@ class AlgorithmTests: XCTestCase {
149212
XCTAssert(type(of: splitParamsRef) == ((Character, Int, Bool) -> [Substring]).self)
150213
}
151214

215+
func testSplitSourceCompatibility() {
216+
CountedOptionSet.arrayLiteralCreationCount = 0
217+
218+
let both: CountedOptionSet = [.one, .two]
219+
let none: CountedOptionSet = []
220+
XCTAssertEqual(CountedOptionSet.arrayLiteralCreationCount, 2)
221+
222+
let cosArray = [both, .one, .two]
223+
XCTAssertEqual(cosArray.split(separator: none).count, 1)
224+
225+
// This tests that `contains([])` uses the element-based `contains(_:)`
226+
// method, interpreting `[]` as an instance of `CountedOptionSet`, rather
227+
// than the collection-based overload, which would interpret `[]` as an
228+
// `Array<CountedOptionSet>`.
229+
XCTAssertEqual(cosArray.split(separator: []).count, 1)
230+
XCTAssertEqual(CountedOptionSet.arrayLiteralCreationCount, 3)
231+
}
232+
152233
func testSplitPermutations() throws {
153234
let splitRegex = try Regex(#"\|"#)
154235
XCTAssertEqual(
@@ -276,7 +357,7 @@ class AlgorithmTests: XCTestCase {
276357
XCTAssertEqual("a ".trimmingPrefix(while: \.isWhitespace), "a ")
277358
}
278359

279-
func testReplace() {
360+
func testRegexReplace() {
280361
func expectReplace(
281362
_ string: String,
282363
_ regex: String,
@@ -300,8 +381,33 @@ class AlgorithmTests: XCTestCase {
300381
expectReplace("aab", "a", "X", "XXb")
301382
expectReplace("aab", "a+", "X", "Xb")
302383
expectReplace("aab", "a*", "X", "XXbX")
384+
385+
// FIXME: Test maxReplacements
386+
// FIXME: Test closure-based replacement
303387
}
304388

389+
func testStringReplace() {
390+
func expectReplace(
391+
_ string: String,
392+
_ pattern: String,
393+
_ replacement: String,
394+
_ expected: String,
395+
file: StaticString = #file, line: UInt = #line
396+
) {
397+
let actual = string.replacing(pattern, with: replacement)
398+
XCTAssertEqual(actual, expected, file: file, line: line)
399+
}
400+
401+
expectReplace("", "", "X", "X")
402+
expectReplace("", "x", "X", "")
403+
expectReplace("a", "", "X", "XaX")
404+
expectReplace("a", "x", "X", "a")
405+
expectReplace("a", "a", "X", "X")
406+
expectReplace("aab", "a", "X", "XXb")
407+
408+
// FIXME: Test maxReplacements
409+
}
410+
305411
func testSubstring() throws {
306412
let s = "aaa | aaaaaa | aaaaaaaaaa"
307413
let s1 = s.dropFirst(6) // "aaaaaa | aaaaaaaaaa"

0 commit comments

Comments
 (0)