Files
swift-mirror/test/stdlib/StringAPICString.swift
Guillaume Lessard c30307e21f [test] replace uses of String(validatingUTF8:)
- use the new name `String(validatingCString:)`
2023-09-11 14:17:05 -07:00

507 lines
15 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. 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
//
// Tests for the non-Foundation CString-oriented API of String
//
import StdlibUnittest
#if os(WASI)
let enableCrashTests = false
#else
let enableCrashTests = true
#endif
var CStringTests = TestSuite("CStringTests")
func getNullUTF8() -> UnsafeMutablePointer<UInt8>? {
return nil
}
func getASCIIUTF8() -> (UnsafeMutablePointer<UInt8>, dealloc: () -> ()) {
let up = UnsafeMutablePointer<UInt8>.allocate(capacity: 100)
up[0] = 0x61
up[1] = 0x62
up[2] = 0
return (up, { up.deallocate() })
}
func getNonASCIIUTF8() -> (UnsafeMutablePointer<UInt8>, dealloc: () -> ()) {
let up = UnsafeMutablePointer<UInt8>.allocate(capacity: 100)
up[0] = 0xd0
up[1] = 0xb0
up[2] = 0xd0
up[3] = 0xb1
up[4] = 0
return (UnsafeMutablePointer(up), { up.deallocate() })
}
func getIllFormedUTF8String1(
) -> (UnsafeMutablePointer<UInt8>, dealloc: () -> ()) {
let up = UnsafeMutablePointer<UInt8>.allocate(capacity: 100)
up[0] = 0x41
up[1] = 0xed
up[2] = 0xa0
up[3] = 0x80
up[4] = 0x41
up[5] = 0
return (UnsafeMutablePointer(up), { up.deallocate() })
}
func getIllFormedUTF8String2(
) -> (UnsafeMutablePointer<UInt8>, dealloc: () -> ()) {
let up = UnsafeMutablePointer<UInt8>.allocate(capacity: 100)
up[0] = 0x41
up[0] = 0x41
up[1] = 0xed
up[2] = 0xa0
up[3] = 0x81
up[4] = 0x41
up[5] = 0
return (UnsafeMutablePointer(up), { up.deallocate() })
}
func asCCharArray(_ a: [UInt8]) -> [CChar] {
return a.map { CChar(bitPattern: $0) }
}
func getUTF8Length(_ cString: UnsafePointer<UInt8>) -> Int {
var length = 0
while cString[length] != 0 {
length += 1
}
return length
}
func bindAsCChar(_ utf8: UnsafePointer<UInt8>) -> UnsafePointer<CChar> {
return UnsafeRawPointer(utf8).bindMemory(to: CChar.self,
capacity: getUTF8Length(utf8))
}
func expectEqualCString(_ lhs: UnsafePointer<UInt8>,
_ rhs: UnsafePointer<UInt8>) {
var index = 0
while lhs[index] != 0 {
expectEqual(lhs[index], rhs[index])
index += 1
}
expectEqual(0, rhs[index])
}
func expectEqualCString(_ lhs: UnsafePointer<UInt8>,
_ rhs: ContiguousArray<UInt8>) {
rhs.withUnsafeBufferPointer {
expectEqualCString(lhs, $0.baseAddress!)
}
}
func expectEqualCString(_ lhs: UnsafePointer<UInt8>,
_ rhs: ContiguousArray<CChar>) {
rhs.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(
to: UInt8.self, capacity: rhs.count) {
expectEqualCString(lhs, $0)
}
}
}
CStringTests.test("String.init(validatingCString:)") {
do {
let (s, dealloc) = getASCIIUTF8()
expectEqual("ab", String(validatingCString: bindAsCChar(s)))
dealloc()
}
do {
let (s, dealloc) = getNonASCIIUTF8()
expectEqual("аб", String(validatingCString: bindAsCChar(s)))
dealloc()
}
do {
let (s, dealloc) = getIllFormedUTF8String1()
expectNil(String(validatingCString: bindAsCChar(s)))
dealloc()
}
}
CStringTests.test("String(cString:)") {
do {
let (s, dealloc) = getASCIIUTF8()
let result = String(cString: s)
expectEqual("ab", result)
let su = bindAsCChar(s)
expectEqual("ab", String(cString: su))
dealloc()
}
do {
let (s, dealloc) = getNonASCIIUTF8()
let result = String(cString: s)
expectEqual("аб", result)
let su = bindAsCChar(s)
expectEqual("аб", String(cString: su))
dealloc()
}
do {
let (s, dealloc) = getIllFormedUTF8String1()
let result = String(cString: s)
expectEqual("\u{41}\u{fffd}\u{fffd}\u{fffd}\u{41}", result)
let su = bindAsCChar(s)
expectEqual("\u{41}\u{fffd}\u{fffd}\u{fffd}\u{41}", String(cString: su))
dealloc()
}
}
CStringTests.test("String.decodeCString") {
do {
let s = getNullUTF8()
let result = String.decodeCString(s, as: UTF8.self)
expectNil(result)
}
do { // repairing
let (s, dealloc) = getIllFormedUTF8String1()
if let (result, repairsMade) = String.decodeCString(
s, as: UTF8.self, repairingInvalidCodeUnits: true) {
expectEqual("\u{41}\u{fffd}\u{fffd}\u{fffd}\u{41}", result)
expectTrue(repairsMade)
} else {
expectUnreachable("Expected .some()")
}
dealloc()
}
do { // non repairing
let (s, dealloc) = getIllFormedUTF8String1()
let result = String.decodeCString(
s, as: UTF8.self, repairingInvalidCodeUnits: false)
expectNil(result)
dealloc()
}
}
CStringTests.test("String.utf8CString") {
do {
let (cstr, dealloc) = getASCIIUTF8()
defer { dealloc() }
let str = String(cString: cstr)
expectEqualCString(cstr, str.utf8CString)
}
do {
let (cstr, dealloc) = getNonASCIIUTF8()
defer { dealloc() }
let str = String(cString: cstr)
expectEqualCString(cstr, str.utf8CString)
}
}
CStringTests.test("String.withCString") {
do {
let (cstr, dealloc) = getASCIIUTF8()
defer { dealloc() }
let str = String(cString: cstr)
str.withCString {
expectEqual(str, String(cString: $0))
}
}
do {
let (cstr, dealloc) = getASCIIUTF8()
defer { dealloc() }
let str = String(cString: cstr)
str.withCString {
expectEqual(str, String(cString: $0))
}
}
}
CStringTests.test("Substring.withCString") {
do {
let (cstr, dealloc) = getASCIIUTF8()
defer { dealloc() }
let str = String(cString: cstr).dropFirst()
str.withCString {
expectEqual(str, String(cString: $0))
}
}
do {
let (cstr, dealloc) = getASCIIUTF8()
defer { dealloc() }
let str = String(cString: cstr).dropFirst()
str.withCString {
expectEqual(str, String(cString: $0))
}
}
}
CStringTests.test("String.cString.with.Array.UInt8.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
do {
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
let cstr = UnsafePointer(u8p)
let buffer = UnsafeBufferPointer(start: cstr, count: getUTF8Length(u8p)+1)
let str = String(cString: Array(buffer))
str.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: buffer.count) {
expectEqualCString(u8p, $0)
}
}
}
guard enableCrashTests else { return }
// no need to test every case; that is covered in other tests
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(cString:) must be null-terminated"
)
_ = String(cString: [] as [UInt8])
expectUnreachable()
}
CStringTests.test("String.cString.with.Array.CChar.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
do {
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
let buffer = UnsafeBufferPointer(start: u8p, count: getUTF8Length(u8p)+1)
let str = buffer.withMemoryRebound(to: CChar.self) {
String(cString: Array($0))
}
str.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: buffer.count) {
expectEqualCString(u8p, $0)
}
}
}
guard enableCrashTests else { return }
// no need to test every case; that is covered in other tests
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(cString:) must be null-terminated"
)
_ = String(cString: [] as [CChar])
expectUnreachable()
}
CStringTests.test("String.cString.with.String.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
var str = String(cString: "ab")
str.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: getUTF8Length(u8p)+1) {
expectEqualCString(u8p, $0)
}
}
str = String(cString: "")
expectTrue(str.isEmpty)
}
CStringTests.test("String.cString.with.inout.UInt8.conversion") {
guard #available(SwiftStdlib 5.7, *) else { return }
var c = UInt8.zero
var str = String(cString: &c)
expectTrue(str.isEmpty)
c = 100
guard enableCrashTests else { return }
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(cString:) must be null-terminated"
)
str = String(cString: &c)
expectUnreachable()
}
CStringTests.test("String.cString.with.inout.CChar.conversion") {
guard #available(SwiftStdlib 5.7, *) else { return }
var c = CChar.zero
var str = String(cString: &c)
expectTrue(str.isEmpty)
c = 100
guard enableCrashTests else { return }
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(cString:) must be null-terminated"
)
str = String(cString: &c)
expectUnreachable()
}
CStringTests.test("String.validatingCString.with.Array.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
do {
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
let buffer = UnsafeBufferPointer(start: u8p, count: getUTF8Length(u8p)+1)
let str = buffer.withMemoryRebound(to: CChar.self) {
String(validatingCString: Array($0))
}
expectNotNil(str)
str?.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: buffer.count) {
expectEqualCString(u8p, $0)
}
}
}
guard enableCrashTests else { return }
// no need to test every case; that is covered in other tests
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(validatingCString:) must be null-terminated"
)
_ = String(validatingCString: [])
expectUnreachable()
}
CStringTests.test("String.validatingCString.with.String.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
var str = String(validatingCString: "ab")
expectNotNil(str)
str?.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: getUTF8Length(u8p)+1) {
expectEqualCString(u8p, $0)
}
}
str = String(validatingCString: "")
expectNotNil(str)
expectEqual(str?.isEmpty, true)
}
CStringTests.test("String.validatingCString.with.inout.conversion") {
guard #available(SwiftStdlib 5.7, *) else { return }
var c = CChar.zero
var str = String(validatingCString: &c)
expectNotNil(str)
expectEqual(str?.isEmpty, true)
c = 100
guard enableCrashTests else { return }
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(validatingCString:) must be null-terminated"
)
str = String(validatingCString: &c)
expectUnreachable()
}
CStringTests.test("String.decodeCString.with.Array.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
do {
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
let buffer = UnsafeBufferPointer(start: u8p, count: getUTF8Length(u8p)+1)
let result = buffer.withMemoryRebound(to: Unicode.UTF8.CodeUnit.self) {
String.decodeCString(Array($0), as: Unicode.UTF8.self)
}
expectNotNil(result)
expectEqual(result?.repairsMade, false)
result?.result.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: buffer.count) {
expectEqualCString(u8p, $0)
}
}
}
guard enableCrashTests else { return }
// no need to test every case; that is covered in other tests
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of decodeCString(_:as:repairingInvalidCodeUnits:) must be null-terminated"
)
_ = String.decodeCString([], as: Unicode.UTF8.self)
expectUnreachable()
}
CStringTests.test("String.decodeCString.with.String.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
var result = String.decodeCString(
"ab", as: Unicode.UTF8.self, repairingInvalidCodeUnits: true
)
expectNotNil(result)
expectEqual(result?.repairsMade, false)
result?.result.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: getUTF8Length(u8p)+1) {
expectEqualCString(u8p, $0)
}
}
result = String.decodeCString("", as: Unicode.UTF8.self)
expectNotNil(result)
expectEqual(result?.repairsMade, false)
expectEqual(result?.result.isEmpty, true)
}
CStringTests.test("String.decodeCString.with.inout.conversion") {
guard #available(SwiftStdlib 5.7, *) else { return }
var c = Unicode.UTF8.CodeUnit.zero
var result = String.decodeCString(
&c, as: Unicode.UTF8.self, repairingInvalidCodeUnits: true
)
expectNotNil(result)
expectEqual(result?.result.isEmpty, true)
expectEqual(result?.repairsMade, false)
c = 100
guard enableCrashTests else { return }
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of decodeCString(_:as:repairingInvalidCodeUnits:) must be null-terminated"
)
result = String.decodeCString(&c, as: Unicode.UTF8.self)
expectUnreachable()
}
CStringTests.test("String.init.decodingCString.with.Array.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
do {
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
let buffer = UnsafeBufferPointer(start: u8p, count: getUTF8Length(u8p)+1)
let str = buffer.withMemoryRebound(to: Unicode.UTF8.CodeUnit.self) {
String(decodingCString: Array($0), as: Unicode.UTF8.self)
}
str.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: buffer.count) {
expectEqualCString(u8p, $0)
}
}
}
guard enableCrashTests else { return }
// no need to test every case; that is covered in other tests
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of decodeCString(_:as:repairingInvalidCodeUnits:) must be null-terminated"
)
_ = String(decodingCString: [], as: Unicode.UTF8.self)
expectUnreachable()
}
CStringTests.test("String.init.decodingCString.with.String.input") {
guard #available(SwiftStdlib 5.7, *) else { return }
let (u8p, dealloc) = getASCIIUTF8()
defer { dealloc() }
var str = String(decodingCString: "ab", as: Unicode.UTF8.self)
str.withCString {
$0.withMemoryRebound(to: UInt8.self, capacity: getUTF8Length(u8p)+1) {
expectEqualCString(u8p, $0)
}
}
str = String(decodingCString: "", as: Unicode.UTF8.self)
expectTrue(str.isEmpty)
}
CStringTests.test("String.init.decodingCString.with.inout.conversion") {
guard #available(SwiftStdlib 5.7, *) else { return }
var c = Unicode.UTF8.CodeUnit.zero
var str = String(decodingCString: &c, as: Unicode.UTF8.self)
expectEqual(str.isEmpty, true)
c = 100
guard enableCrashTests else { return }
expectCrashLater(
// Workaround for https://github.com/apple/swift/issues/58362 (rdar://91365967)
// withMessage: "input of String.init(decodingCString:as:) must be null-terminated"
)
str = String(decodingCString: &c, as: Unicode.UTF8.self)
expectUnreachable()
}
runAllTests()