Skip to content

Commit ce09452

Browse files
committed
Increase algorithms test coverage
1 parent f779459 commit ce09452

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,
@@ -75,6 +115,7 @@ class AlgorithmTests: XCTestCase {
75115
expectRanges("", "x", [])
76116
expectRanges("", "x+", [])
77117
expectRanges("", "x*", [0..<0])
118+
expectRanges("aaa", "a*", [0..<3, 3..<3])
78119
expectRanges("abc", "", [0..<0, 1..<1, 2..<2, 3..<3])
79120
expectRanges("abc", "x", [])
80121
expectRanges("abc", "x+", [])
@@ -89,8 +130,10 @@ class AlgorithmTests: XCTestCase {
89130
expectRanges("abc", "(a|b)*", [0..<2, 2..<2, 3..<3])
90131
expectRanges("abc", "(b|c)+", [1..<3])
91132
expectRanges("abc", "(b|c)*", [0..<0, 1..<3, 3..<3])
92-
93-
func expectStringRanges(
133+
}
134+
135+
func testStringRanges() {
136+
func expectRanges(
94137
_ input: String,
95138
_ pattern: String,
96139
_ expected: [Range<Int>],
@@ -107,16 +150,16 @@ class AlgorithmTests: XCTestCase {
107150
XCTAssertEqual(firstRange, expected.first, file: file, line: line)
108151
}
109152

110-
expectStringRanges("", "", [0..<0])
111-
expectStringRanges("abcde", "", [0..<0, 1..<1, 2..<2, 3..<3, 4..<4, 5..<5])
112-
expectStringRanges("abcde", "abcd", [0..<4])
113-
expectStringRanges("abcde", "bcde", [1..<5])
114-
expectStringRanges("abcde", "bcd", [1..<4])
115-
expectStringRanges("ababacabababa", "abababa", [6..<13])
116-
expectStringRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13])
153+
expectRanges("", "", [0..<0])
154+
expectRanges("abcde", "", [0..<0, 1..<1, 2..<2, 3..<3, 4..<4, 5..<5])
155+
expectRanges("abcde", "abcd", [0..<4])
156+
expectRanges("abcde", "bcde", [1..<5])
157+
expectRanges("abcde", "bcd", [1..<4])
158+
expectRanges("ababacabababa", "abababa", [6..<13])
159+
expectRanges("ababacabababa", "aba", [0..<3, 6..<9, 10..<13])
117160
}
118161

119-
func testSplit() {
162+
func testRegexSplit() {
120163
func expectSplit(
121164
_ string: String,
122165
_ regex: String,
@@ -135,6 +178,26 @@ class AlgorithmTests: XCTestCase {
135178
expectSplit("a", "a", ["", ""])
136179
expectSplit("a____a____a", "_+", ["a", "a", "a"])
137180
expectSplit("____a____a____a____", "_+", ["", "a", "a", "a", ""])
181+
}
182+
183+
func testStringSplit() {
184+
func expectSplit(
185+
_ string: String,
186+
_ separator: String,
187+
_ expected: [Substring],
188+
file: StaticString = #file, line: UInt = #line
189+
) {
190+
let actual = Array(string.split(separator: separator, omittingEmptySubsequences: false))
191+
XCTAssertEqual(actual, expected, file: file, line: line)
192+
}
193+
194+
expectSplit("", "", [""])
195+
expectSplit("", "x", [""])
196+
expectSplit("a", "", ["", "a", ""])
197+
expectSplit("a", "x", ["a"])
198+
expectSplit("a", "a", ["", ""])
199+
expectSplit("a__a__a", "_", ["a", "", "a", "", "a"])
200+
expectSplit("_a_a_a_", "_", ["", "a", "a", "a", ""])
138201

139202
XCTAssertEqual("".split(separator: ""), [])
140203
XCTAssertEqual("".split(separator: "", omittingEmptySubsequences: false), [""])
@@ -146,6 +209,24 @@ class AlgorithmTests: XCTestCase {
146209
XCTAssert(type(of: splitParamsRef) == ((Character, Int, Bool) -> [Substring]).self)
147210
}
148211

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

276-
func testReplace() {
357+
func testRegexReplace() {
277358
func expectReplace(
278359
_ string: String,
279360
_ regex: String,
@@ -297,8 +378,33 @@ class AlgorithmTests: XCTestCase {
297378
expectReplace("aab", "a", "X", "XXb")
298379
expectReplace("aab", "a+", "X", "Xb")
299380
expectReplace("aab", "a*", "X", "XXbX")
381+
382+
// FIXME: Test maxReplacements
383+
// FIXME: Test closure-based replacement
300384
}
301385

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

0 commit comments

Comments
 (0)