Files
swift-mirror/test/stdlib/subString.swift
Guillaume Lessard 694a9bef2a [test] fix for backdeployment testing
These were using the wrong availability macro for the purpose of limiting backdeployment testing.
2026-02-27 11:33:17 -08:00

462 lines
14 KiB
Swift

// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// UNSUPPORTED: freestanding
import StdlibUnittest
var SubstringTests = TestSuite("SubstringTests")
func checkMatch<S: Collection, T: Collection>(_ x: S, _ y: T, _ i: S.Index)
where S.Index == T.Index, S.Iterator.Element == T.Iterator.Element,
S.Iterator.Element: Equatable
{
expectEqual(x[i], y[i])
}
func checkMatchContiguousStorage<S: Collection, T: Collection>(_ x: S, _ y: T)
where S.Element == T.Element, S.Element: Equatable
{
let xElement = x.withContiguousStorageIfAvailable { $0.first }
let yElement = y.withContiguousStorageIfAvailable { $0.first }
expectEqual(xElement, yElement)
}
func checkHasContiguousStorage<S: Collection>(_ x: S) {
expectTrue(x.withContiguousStorageIfAvailable { _ in true } ?? false)
}
func checkHasContiguousStorageSubstring(_ x: Substring.UTF8View) {
let hasStorage = x.withContiguousStorageIfAvailable { _ in true } ?? false
expectTrue(hasStorage)
}
fileprivate func slices(
_ s: String,
from: Int,
to: Int
) -> (
Substring,
Substring,
Substring
) {
let s1 = s[s.index(s.startIndex, offsetBy: from) ..<
s.index(s.startIndex, offsetBy: to)]
let s2 = s1[s1.startIndex..<s1.endIndex]
let s3 = s2[s1.startIndex..<s1.endIndex]
return (s1, s2, s3)
}
fileprivate func allNotEmpty(
_ s: Substring...
) -> Bool {
s.allSatisfy { $0.isEmpty == false }
}
fileprivate func allEqual(
_ s: Substring...
) -> Bool {
for i in 0..<s.count {
for j in (i + 1)..<s.count {
if s[i] != s[j] {
return false
}
}
}
return true
}
SubstringTests.test("Equality") {
let s = "abcdefg"
let s1 = s[s.index(s.startIndex, offsetBy: 2) ..<
s.index(s.startIndex, offsetBy: 4)]
let s2 = s1[s1.startIndex..<s1.endIndex]
let s3 = s2[s1.startIndex..<s1.endIndex]
expectEqual(s1, "cd")
expectEqual(s2, "cd")
expectEqual(s3, "cd")
expectTrue("" == s.dropFirst(s.count))
expectTrue(s.dropFirst().dropFirst(s.count) == s.dropFirst(s.count))
expectEqual("ab" as String, s.prefix(2))
expectEqual("fg" as String, s.suffix(2))
#if _runtime(_ObjC)
expectTrue(s == s[...])
expectTrue(s[...] == s)
expectTrue(s.dropFirst(2) != s)
expectTrue(s == s.dropFirst(0))
expectTrue(s != s.dropFirst(1))
expectTrue(s != s.dropLast(1))
expectEqual(s[...], s[...])
expectEqual(s.dropFirst(0), s.dropFirst(0))
expectTrue(s == s.dropFirst(0))
expectTrue(s.dropFirst(2) != s.dropFirst(1))
expectNotEqual(s.dropLast(2), s.dropLast(1))
expectEqual(s.dropFirst(1), s.dropFirst(1))
expectTrue(s != s[...].dropFirst(1))
#endif
// equatable conformance
expectTrue("one,two,three".split(separator: ",").contains("two"))
expectTrue("one,two,three".split(separator: ",") == ["one","two","three"])
}
#if _runtime(_ObjC)
SubstringTests.test("Equality/Emoji")
.xfail(.osxMinor(10, 9, reason: "Mac OS X 10.9 has an old ICU"))
.xfail(.iOSMajor(7, reason: "iOS 7 has an old ICU"))
.code {
let s = "abcdefg"
let emoji: String = s + "😄👍🏽🇫🇷👩‍👩‍👧‍👦🙈" + "😡🇧🇪🇨🇦🇮🇳"
let i = emoji.firstIndex(of: "😄")!
expectEqual("😄👍🏽" as String, emoji[i...].prefix(2))
expectTrue("😄👍🏽🇫🇷👩‍👩‍👧‍👦🙈😡🇧🇪" as String == emoji[i...].dropLast(2))
expectTrue("🇫🇷👩‍👩‍👧‍👦🙈😡🇧🇪" as String == emoji[i...].dropLast(2).dropFirst(2))
expectTrue(s as String != emoji[i...].dropLast(2).dropFirst(2))
expectEqualSequence("😄👍🏽🇫🇷👩‍👩‍👧‍👦🙈😡🇧🇪" as String, emoji[i...].dropLast(2))
expectEqualSequence("🇫🇷👩‍👩‍👧‍👦🙈😡🇧🇪" as String, emoji[i...].dropLast(2).dropFirst(2))
}
#endif
SubstringTests.test("Comparison") {
var s = "abc"
s += "defg"
expectFalse(s < s[...])
expectTrue(s <= s[...])
expectTrue(s >= s[...])
expectFalse(s > s[...])
expectFalse(s[...] < s)
expectTrue(s[...] <= s)
expectTrue(s[...] >= s)
expectFalse(s[...] > s)
expectFalse(s[...] < s[...])
expectTrue(s[...] <= s[...])
expectTrue(s[...] >= s[...])
expectFalse(s[...] > s[...])
expectTrue(s < s.dropFirst())
expectFalse(s > s.dropFirst())
expectFalse(s < s.dropLast())
expectTrue(s > s.dropLast())
expectTrue(s.dropFirst() < s.dropFirst(2))
expectFalse(s.dropFirst() > s.dropFirst(2))
expectFalse(s.dropLast() < s.dropLast(2))
expectTrue(s.dropLast() > s.dropLast(2))
expectFalse(s.dropFirst() < s.dropFirst().dropLast())
expectTrue(s.dropFirst() > s.dropFirst().dropLast())
expectTrue(s.dropFirst() > s)
expectTrue(s.dropFirst() > s[...])
expectTrue(s >= s[...])
expectTrue(s.dropFirst() >= s.dropFirst())
// comparable conformance
expectEqualSequence("pen,pineapple,apple,pen".split(separator: ",").sorted(),
["apple", "pen", "pen", "pineapple"])
}
SubstringTests.test("Filter") {
var name = "😂Edward Woodward".dropFirst()
var filtered = name.filter { $0 != "d" }
expectType(Substring.self, &name)
expectType(String.self, &filtered)
expectEqual("Ewar Woowar", filtered)
}
SubstringTests.test("CharacterView") {
let s = "abcdefg"
var t = s.dropFirst(2)
var u = t.dropFirst(2)
checkMatch(s, t, t.startIndex)
checkMatch(s, t, t.index(after: t.startIndex))
checkMatch(s, t, t.index(before: t.endIndex))
checkMatch(s, t, u.startIndex)
checkMatch(t, u, u.startIndex)
checkMatch(t, u, u.index(after: u.startIndex))
checkMatch(t, u, u.index(before: u.endIndex))
expectEqual("", String(t.dropFirst(10)))
expectEqual("", String(t.dropLast(10)))
expectEqual("", String(u.dropFirst(10)))
expectEqual("", String(u.dropLast(10)))
t.replaceSubrange(t.startIndex...t.startIndex, with: ["C"])
u.replaceSubrange(u.startIndex...u.startIndex, with: ["E"])
expectEqual(String(u), "Efg")
expectEqual(String(t), "Cdefg")
expectEqual(s, "abcdefg")
}
SubstringTests.test("UnicodeScalars") {
let s = "abcdefg"
var t = s.unicodeScalars.dropFirst(2)
var u = t.dropFirst(2)
checkMatch(s.unicodeScalars, t, t.startIndex)
checkMatch(s.unicodeScalars, t, t.index(after: t.startIndex))
checkMatch(s.unicodeScalars, t, t.index(before: t.endIndex))
checkMatch(s.unicodeScalars, t, u.startIndex)
checkMatch(t, u, u.startIndex)
checkMatch(t, u, u.index(after: u.startIndex))
checkMatch(t, u, u.index(before: u.endIndex))
expectEqual("", String(t.dropFirst(10)))
expectEqual("", String(t.dropLast(10)))
expectEqual("", String(u.dropFirst(10)))
expectEqual("", String(u.dropLast(10)))
t.replaceSubrange(t.startIndex...t.startIndex, with: ["C"])
u.replaceSubrange(u.startIndex...u.startIndex, with: ["E"])
expectEqual(String(u), "Efg")
expectEqual(String(t), "Cdefg")
expectEqual(s, "abcdefg")
}
SubstringTests.test("UTF16View") {
let s = "abcdefg"
let t = s.utf16.dropFirst(2)
let u = t.dropFirst(2)
checkMatch(s.utf16, t, t.startIndex)
checkMatch(s.utf16, t, t.index(after: t.startIndex))
checkMatch(s.utf16, t, t.index(before: t.endIndex))
checkMatch(s.utf16, t, u.startIndex)
checkMatch(t, u, u.startIndex)
checkMatch(t, u, u.index(after: u.startIndex))
checkMatch(t, u, u.index(before: u.endIndex))
expectEqual("", String(t.dropFirst(10))!)
expectEqual("", String(t.dropLast(10))!)
expectEqual("", String(u.dropFirst(10))!)
expectEqual("", String(u.dropLast(10))!)
}
SubstringTests.test("Mutate Substring through utf16 view") {
let s = "abcdefg"
var ss = s[...]
expectEqual(s.startIndex, ss.startIndex)
expectEqual(s.count, ss.count)
let first = ss.utf16.removeFirst()
expectEqual(first, UInt16(97))
expectEqual(s.index(after: s.startIndex), ss.startIndex)
expectEqual(s.count - 1, ss.count)
}
SubstringTests.test("Mutate Substring through unicodeScalars view") {
let s = "abcdefg"
var ss = s[...]
expectEqual(s.startIndex, ss.startIndex)
expectEqual(s.count, ss.count)
ss.unicodeScalars.append("h")
expectEqual(s.startIndex, ss.startIndex)
expectEqual(s.count + 1, ss.count)
expectEqual(ss.last, "h")
expectEqual(s.last, "g")
}
SubstringTests.test("UTF8View") {
let strs = [
"abcdefg", // Small ASCII
"abéÏ", // Small Unicode
"012345678901234567890", // Large ASCII
"abéÏ012345678901234567890", // Large Unicode
]
for s in strs {
let t = s.utf8.dropFirst(2)
let u = t.dropFirst(2)
checkMatch(s.utf8, t, t.startIndex)
checkMatch(s.utf8, t, t.index(after: t.startIndex))
checkMatch(s.utf8, t, u.startIndex)
checkMatch(t, u, u.startIndex)
checkMatch(t, u, u.index(after: u.startIndex))
expectEqual("", String(t.dropFirst(100))!)
expectEqual("", String(t.dropLast(100))!)
expectEqual("", String(u.dropFirst(100))!)
expectEqual("", String(u.dropLast(100))!)
checkHasContiguousStorage(s.utf8) // Strings always do
checkHasContiguousStorageSubstring(t)
checkHasContiguousStorageSubstring(u)
checkMatchContiguousStorage(Array(s.utf8), s.utf8)
// The specialization for Substring.UTF8View.withContiguousStorageIfAvailable
// was added in https://github.com/apple/swift/pull/29146.
guard #available(SwiftStdlib 5.3, *) else {
return
}
checkHasContiguousStorage(t)
checkHasContiguousStorage(u)
checkMatchContiguousStorage(Array(t), t)
checkMatchContiguousStorage(Array(u), u)
}
}
SubstringTests.test("Persistent Content") {
var str = "abc"
str += "def"
expectEqual("bcdefg", str.dropFirst(1) + "g")
expectEqual("bcdefg", (str.dropFirst(1) + "g") as String)
}
SubstringTests.test("Substring.base") {
let str = "abéÏ01😓🎃👨‍👨‍👧‍👦"
expectEqual(str, str.dropLast().base)
for idx in str.indices {
expectEqual(str, str[idx...].base)
expectEqual(str, str[...idx].base)
}
}
SubstringTests.test("isTriviallyIdentical(to:) small ascii")
.require(.stdlib_6_4).code {
guard #available(SwiftStdlib 6.4, *) else { return }
let a = "Hello"
let b = "Hello"
precondition(a == b)
let (a1, a2, a3) = slices(a, from: 2, to: 4)
let (b1, b2, b3) = slices(b, from: 2, to: 4)
precondition(allNotEmpty(a1, a2, a3, b1, b2, b3))
precondition(allEqual(a1, a2, a3, b1, b2, b3))
expectTrue(a1.isTriviallyIdentical(to: a1))
expectTrue(a1.isTriviallyIdentical(to: a2))
expectTrue(a1.isTriviallyIdentical(to: a3))
expectTrue(a1.isTriviallyIdentical(to: b1))
expectTrue(a1.isTriviallyIdentical(to: b2))
expectTrue(a1.isTriviallyIdentical(to: b3))
expectTrue(a2.isTriviallyIdentical(to: a1))
expectTrue(a2.isTriviallyIdentical(to: a2))
expectTrue(a2.isTriviallyIdentical(to: a3))
expectTrue(a2.isTriviallyIdentical(to: b1))
expectTrue(a2.isTriviallyIdentical(to: b2))
expectTrue(a2.isTriviallyIdentical(to: b3))
expectTrue(a3.isTriviallyIdentical(to: a1))
expectTrue(a3.isTriviallyIdentical(to: a2))
expectTrue(a3.isTriviallyIdentical(to: a3))
expectTrue(a3.isTriviallyIdentical(to: b1))
expectTrue(a3.isTriviallyIdentical(to: b2))
expectTrue(a3.isTriviallyIdentical(to: b3))
let c = "Hello"
precondition(b == c)
let (c1, c2, c3) = slices(c, from: 1, to: 3)
expectFalse(a1.isTriviallyIdentical(to: c1))
expectFalse(a1.isTriviallyIdentical(to: c2))
expectFalse(a1.isTriviallyIdentical(to: c3))
expectFalse(a2.isTriviallyIdentical(to: c1))
expectFalse(a2.isTriviallyIdentical(to: c2))
expectFalse(a2.isTriviallyIdentical(to: c3))
expectFalse(a3.isTriviallyIdentical(to: c1))
expectFalse(a3.isTriviallyIdentical(to: c2))
expectFalse(a3.isTriviallyIdentical(to: c3))
}
SubstringTests.test("isTriviallyIdentical(to:) small unicode")
.require(.stdlib_6_4).code {
guard #available(SwiftStdlib 6.4, *) else { return }
let a = "Cafe\u{301}"
let b = "Cafe\u{301}"
let c = "Café"
precondition(a == b)
precondition(b == c)
let (a1, a2, a3) = slices(a, from: 2, to: 4)
let (b1, b2, b3) = slices(b, from: 2, to: 4)
let (c1, c2, c3) = slices(c, from: 2, to: 4)
precondition(allNotEmpty(a1, a2, a3, b1, b2, b3, c1, c2, c3))
precondition(allEqual(a1, a2, a3, b1, b2, b3, c1, c2, c3))
expectTrue(a1.isTriviallyIdentical(to: a1))
expectTrue(a1.isTriviallyIdentical(to: a2))
expectTrue(a1.isTriviallyIdentical(to: a3))
expectTrue(a1.isTriviallyIdentical(to: b1))
expectTrue(a1.isTriviallyIdentical(to: b2))
expectTrue(a1.isTriviallyIdentical(to: b3))
expectFalse(a1.isTriviallyIdentical(to: c1))
expectFalse(a1.isTriviallyIdentical(to: c2))
expectFalse(a1.isTriviallyIdentical(to: c3))
expectTrue(a2.isTriviallyIdentical(to: a1))
expectTrue(a2.isTriviallyIdentical(to: a2))
expectTrue(a2.isTriviallyIdentical(to: a3))
expectTrue(a2.isTriviallyIdentical(to: b1))
expectTrue(a2.isTriviallyIdentical(to: b2))
expectTrue(a2.isTriviallyIdentical(to: b3))
expectFalse(a2.isTriviallyIdentical(to: c1))
expectFalse(a2.isTriviallyIdentical(to: c2))
expectFalse(a2.isTriviallyIdentical(to: c3))
expectTrue(a3.isTriviallyIdentical(to: a1))
expectTrue(a3.isTriviallyIdentical(to: a2))
expectTrue(a3.isTriviallyIdentical(to: a3))
expectTrue(a3.isTriviallyIdentical(to: b1))
expectTrue(a3.isTriviallyIdentical(to: b2))
expectTrue(a3.isTriviallyIdentical(to: b3))
expectFalse(a3.isTriviallyIdentical(to: c1))
expectFalse(a3.isTriviallyIdentical(to: c2))
expectFalse(a3.isTriviallyIdentical(to: c3))
}
SubstringTests.test("isTriviallyIdentical(to:) large ascii")
.require(.stdlib_6_4).code {
guard #available(SwiftStdlib 6.4, *) else { return }
let a = String(repeating: "foo", count: 1000)
let b = String(repeating: "foo", count: 1000)
precondition(a == b)
let (a1, a2, a3) = slices(a, from: 2, to: 4)
let (b1, b2, b3) = slices(b, from: 2, to: 4)
precondition(allNotEmpty(a1, a2, a3, b1, b2, b3))
precondition(allEqual(a1, a2, a3, b1, b2, b3))
expectTrue(a1.isTriviallyIdentical(to: a1))
expectTrue(a1.isTriviallyIdentical(to: a2))
expectTrue(a1.isTriviallyIdentical(to: a3))
expectFalse(a1.isTriviallyIdentical(to: b1))
expectFalse(a1.isTriviallyIdentical(to: b2))
expectFalse(a1.isTriviallyIdentical(to: b3))
expectTrue(a2.isTriviallyIdentical(to: a1))
expectTrue(a2.isTriviallyIdentical(to: a2))
expectTrue(a2.isTriviallyIdentical(to: a3))
expectFalse(a2.isTriviallyIdentical(to: b1))
expectFalse(a2.isTriviallyIdentical(to: b2))
expectFalse(a2.isTriviallyIdentical(to: b3))
expectTrue(a3.isTriviallyIdentical(to: a1))
expectTrue(a3.isTriviallyIdentical(to: a2))
expectTrue(a3.isTriviallyIdentical(to: a3))
expectFalse(a3.isTriviallyIdentical(to: b1))
expectFalse(a3.isTriviallyIdentical(to: b2))
expectFalse(a3.isTriviallyIdentical(to: b3))
}
runAllTests()