blob: 32512e552bbd9c4e8e040ab99fc8d8fefaea54ab [file] [log] [blame]
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: objc_interop
// REQUIRES: CPU=arm64 || CPU=x86_64
//
// Tests for small strings
//
import StdlibUnittest
import Foundation
var SmallStringTests = TestSuite("SmallStringTests")
extension String: Error {}
func verifySmallString(_ small: _SmallUTF8String, _ input: String) {
expectEqual(_SmallUTF8String.capacity, small.count + small.unusedCapacity)
let tiny = Array(input.utf8)
expectEqual(tiny.count, small.count)
for (lhs, rhs) in zip(tiny, small) {
expectEqual(lhs, rhs)
}
small.withTranscodedUTF16CodeUnits {
let codeUnits = Array(input.utf16)
expectEqualSequence(codeUnits, $0)
}
let smallFromUTF16 = _SmallUTF8String(Array(input.utf16))
expectNotNil(smallFromUTF16)
expectEqualSequence(small, smallFromUTF16!)
// Test slicing
//
for i in 0..<small.count {
for j in i...small.count {
expectEqualSequence(tiny[i..<j], small[i..<j])
if j < small.count {
expectEqualSequence(tiny[i...j], small[i...j])
}
}
}
}
// Testing helper inits
extension _SmallUTF8String {
init?(_ codeUnits: Array<UInt8>) {
guard let smol = codeUnits.withUnsafeBufferPointer({
return _SmallUTF8String($0)
}) else {
return nil
}
self = smol
}
init?(_ codeUnits: Array<UInt16>) {
guard let smol = codeUnits.withUnsafeBufferPointer({
return _SmallUTF8String($0)
}) else {
return nil
}
self = smol
}
}
SmallStringTests.test("FitsInSmall") {
func runTest(_ input: String) throws {
let tiny = Array(input.utf8)
// Constructed from UTF-8 code units
guard let small = _SmallUTF8String(tiny) else {
throw "Didn't fit"
}
verifySmallString(small, input)
// Constructed from UTF-16 code units
guard let fromUTF16Small = _SmallUTF8String(Array(input.utf16)) else {
throw "Failed from utf-16"
}
verifySmallString(fromUTF16Small, input)
}
// Pass tests
//
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTest("abπŸ˜‡c") })
expectDoesNotThrow({ try runTest("0123456789abcde") })
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTest("πŸ‘¨β€πŸ‘¦") })
expectDoesNotThrow({ try runTest("") })
// Fail tests
//
expectThrows("Didn't fit", { try runTest("0123456789abcdef") })
expectThrows("Didn't fit", { try runTest("πŸ‘©β€πŸ‘¦β€πŸ‘¦") })
for cu in (0 as UInt32)...(0x10FFFF as UInt32) {
// TODO: Iterate over all scalars when we support UTF-8, and possibly move
// this to validation suite.
guard let scalar = Unicode.Scalar(cu) else { continue }
guard cu <= 0x7F else { break }
expectDoesNotThrow({ try runTest(String(scalar)) })
}
}
SmallStringTests.test("Bridging") {
// Test bridging retains small string form
func bridge(_ small: _SmallUTF8String) -> String {
return _bridgeToCocoa(small) as! String
}
func runTestSmall(_ input: String) throws {
// Constructed through CF
guard let fromCocoaSmall = _SmallUTF8String(
_cocoaString: input as NSString
) else {
throw "Didn't fit"
}
verifySmallString(fromCocoaSmall, input)
verifySmallString(fromCocoaSmall, bridge(fromCocoaSmall))
}
// Pass tests
//
expectDoesNotThrow({ try runTestSmall("abc") })
expectDoesNotThrow({ try runTestSmall("0123456789abcde") })
expectDoesNotThrow({ try runTestSmall("\u{0}") })
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTestSmall("πŸ‘¨β€πŸ‘¦") })
expectDoesNotThrow({ try runTestSmall("") })
// TODO(UTF-8 SSO): expectDoesNotThrow({ try runTestSmall("πŸ‘¨β€πŸ‘¦abcd") })
// Fail tests
//
expectThrows("Didn't fit", { try runTestSmall("πŸ‘¨β€πŸ‘©β€πŸ‘¦") })
expectThrows("Didn't fit", { try runTestSmall("πŸ‘¨β€πŸ‘¦abcde") })
}
SmallStringTests.test("Append, repeating") {
let strings = [
"",
"a",
"bc",
"def",
"hijk",
"lmnop",
"qrstuv",
"xyzzzzz",
"01234567",
"890123456",
"7890123456",
"78901234567",
"890123456789",
"0123456789012",
"34567890123456",
"789012345678901",
]
let smallstrings = strings.compactMap {
_SmallUTF8String(Array($0.utf8))
}
expectEqual(strings.count, smallstrings.count)
for (small, str) in zip(smallstrings, strings) {
verifySmallString(small, str)
}
for i in 0..<smallstrings.count {
for j in i..<smallstrings.count {
let lhs = smallstrings[i]
let rhs = smallstrings[j]
if lhs.count + rhs.count > _SmallUTF8String.capacity {
continue
}
verifySmallString(lhs._appending(rhs)!, (strings[i] + strings[j]))
verifySmallString(rhs._appending(lhs)!, (strings[j] + strings[i]))
}
}
for i in 0..<smallstrings.count {
for c in 2...15 {
let str = String(repeating: strings[i], count: c)
if let small = smallstrings[i]._repeated(c) {
verifySmallString(small, str)
} else {
expectTrue(str.utf8.count > 15)
}
}
}
}
runAllTests()