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
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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()