Files
swift-mirror/test/Interop/Cxx/stdlib/use-std-string.swift
Egor Zhdan e32e64353f [cxx-interop] Conform std::string to ExpressibleByStringInterpolation
This adds conformances for C++ string types (`std::string`, `std::u16string`, `std::u32string`) to `Swift.ExpressibleByStringInterpolation`.

These conformances currently implicitly use `DefaultStringInterpolation`. In the future we can provide more performant interpolation mechanisms for C++ strings specifically that avoid the extra conversion between Swift String and C++ string types.

rdar://147249169
2025-03-18 15:54:56 +00:00

494 lines
14 KiB
Swift
Raw Permalink Blame History

// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop)
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop -D USE_CUSTOM_STRING_API)
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=swift-6 -D USE_CUSTOM_STRING_API)
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -D USE_CUSTOM_STRING_API)
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -D USE_CUSTOM_STRING_API -Xcc -std=c++14)
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -D USE_CUSTOM_STRING_API -Xcc -std=c++17)
// RUN: %target-run-simple-swift(-I %S/Inputs -cxx-interoperability-mode=upcoming-swift -D USE_CUSTOM_STRING_API -Xcc -std=c++20)
//
// REQUIRES: executable_test
import StdlibUnittest
import CxxStdlib
#if USE_CUSTOM_STRING_API
import StdString
#endif
var StdStringTestSuite = TestSuite("StdString")
StdStringTestSuite.test("init") {
let s = std.string()
expectEqual(s.size(), 0)
expectTrue(s.empty())
}
StdStringTestSuite.test("push back") {
var s = std.string()
s.push_back(42)
expectEqual(s.size(), 1)
expectFalse(s.empty())
expectEqual(s[0], 42)
}
StdStringTestSuite.test("std::string <=> Swift.String") {
let cxx1 = std.string()
let swift1 = String(cxx1)
expectEqual(swift1, "")
let cxx2 = std.string("something123")
let swift2 = String(cxx2)
expectEqual(swift2, "something123")
let cxx3: std.string = "literal"
expectEqual(cxx3.size(), 7)
// Non-ASCII characters are represented by more than one CChar.
let cxx4: std.string = "тест"
expectEqual(cxx4.size(), 8)
let swift4 = String(cxx4)
expectEqual(swift4, "тест")
let cxx5: std.string = "emoji_🤖"
expectEqual(cxx5.size(), 10)
let swift5 = String(cxx5)
expectEqual(swift5, "emoji_🤖")
let cxx6 = std.string("xyz\0abc")
expectEqual(cxx6.size(), 7)
let swift6 = String(cxx6)
expectEqual(swift6, "xyz\0abc")
var cxx7 = std.string()
let bytes: [UInt8] = [0xE1, 0xC1, 0xAC]
for byte in bytes {
cxx7.push_back(CChar(bitPattern: byte))
}
let swift7 = String(cxx7)
expectEqual(swift7, "<EFBFBD><EFBFBD><EFBFBD>")
let cxxLiteral: std.string = "Hello"
let cxx8: std.string = "\(cxxLiteral), World!"
expectEqual(cxx8.size(), 13)
let swift8 = String(cxx8)
expectEqual(swift8, "Hello, World!")
}
StdStringTestSuite.test("std::string operators") {
var s1 = std.string("something")
let s2 = std.string("123")
let sum = s1 + s2
expectEqual(sum, std.string("something123"))
expectFalse(s1 == s2)
let s3 = std.string("something123")
expectFalse(s1 == s3)
expectFalse(s2 == s3)
s1 += s2
expectTrue(s1 == std.string("something123"))
expectTrue(s1 == s3)
// Make sure the operators work together with ExpressibleByStringLiteral conformance.
s1 += "literal"
expectTrue(s1 == "something123literal")
}
StdStringTestSuite.test("std::u16string operators") {
var s1 = std.u16string("something")
let s2 = std.u16string("123")
let sum = s1 + s2
expectEqual(sum, std.u16string("something123"))
expectFalse(s1 == s2)
let s3 = std.u16string("something123")
expectFalse(s1 == s3)
expectFalse(s2 == s3)
s1 += s2
expectTrue(s1 == std.u16string("something123"))
expectTrue(s1 == s3)
// Make sure the operators work together with ExpressibleByStringLiteral conformance.
s1 += "literal"
expectTrue(s1 == "something123literal")
}
StdStringTestSuite.test("std::u32string operators") {
var s1 = std.u32string("something")
let s2 = std.u32string("123")
let sum = s1 + s2
expectEqual(sum, std.u32string("something123"))
expectFalse(s1 == s2)
let s3 = std.u32string("something123")
expectFalse(s1 == s3)
expectFalse(s2 == s3)
s1 += s2
expectTrue(s1 == std.u32string("something123"))
expectTrue(s1 == s3)
// Make sure the operators work together with ExpressibleByStringLiteral conformance.
s1 += "literal"
expectTrue(s1 == "something123literal")
}
StdStringTestSuite.test("std::string::append") {
var s1 = std.string("0123")
let s2 = std.string("abc")
s1.append(s2)
expectEqual(s1, std.string("0123abc"))
}
StdStringTestSuite.test("std::u16string::append") {
var s1 = std.u16string("0123")
let s2 = std.u16string("abc")
s1.append(s2)
expectEqual(s1, std.u16string("0123abc"))
}
StdStringTestSuite.test("std::u32string::append") {
var s1 = std.u32string("0123")
let s2 = std.u32string("abc")
s1.append(s2)
expectEqual(s1, std.u32string("0123abc"))
}
StdStringTestSuite.test("std::string comparison") {
let s1 = std.string("abc")
let s2 = std.string("def")
let s3 = std.string("abc")
expectTrue(s1 < s2)
expectFalse(s2 < s1)
expectTrue(s1 <= s2)
expectFalse(s2 <= s1)
expectTrue(s2 > s1)
expectFalse(s1 > s2)
expectTrue(s2 >= s1)
expectFalse(s1 >= s2)
expectTrue(s1 == s3)
}
StdStringTestSuite.test("std::u16string comparison") {
let s1 = std.u16string("abc")
let s2 = std.u16string("def")
let s3 = std.u16string("abc")
expectTrue(s1 < s2)
expectFalse(s2 < s1)
expectTrue(s1 <= s2)
expectFalse(s2 <= s1)
expectTrue(s2 > s1)
expectFalse(s1 > s2)
expectTrue(s2 >= s1)
expectFalse(s1 >= s2)
expectTrue(s1 == s3)
}
StdStringTestSuite.test("std::u32string comparison") {
let s1 = std.u32string("abc")
let s2 = std.u32string("def")
let s3 = std.u32string("abc")
expectTrue(s1 < s2)
expectFalse(s2 < s1)
expectTrue(s1 <= s2)
expectFalse(s2 <= s1)
expectTrue(s2 > s1)
expectFalse(s1 > s2)
expectTrue(s2 >= s1)
expectFalse(s1 >= s2)
expectTrue(s1 == s3)
}
StdStringTestSuite.test("std::string as Hashable") {
let s0 = std.string()
let h0 = s0.hashValue
let s1 = std.string("something")
let h1 = s1.hashValue
let s2 = std.string("something123")
let h2 = s2.hashValue
let s3 = std.string("something")
let h3 = s3.hashValue
expectEqual(h1, h3)
expectNotEqual(h0, h1)
expectNotEqual(h0, h2)
expectNotEqual(h0, h3)
expectNotEqual(h1, h2)
expectNotEqual(h2, h3)
}
StdStringTestSuite.test("std::u16string as Hashable") {
let s0 = std.u16string()
let h0 = s0.hashValue
let s1 = std.u16string("something")
let h1 = s1.hashValue
let s2 = std.u16string("something123")
let h2 = s2.hashValue
let s3 = std.u16string("something")
let h3 = s3.hashValue
expectEqual(h1, h3)
expectNotEqual(h0, h1)
expectNotEqual(h0, h2)
expectNotEqual(h0, h3)
expectNotEqual(h1, h2)
expectNotEqual(h2, h3)
}
StdStringTestSuite.test("std::u32string as Hashable") {
let s0 = std.u32string()
let h0 = s0.hashValue
let s1 = std.u32string("something")
let h1 = s1.hashValue
let s2 = std.u32string("something123")
let h2 = s2.hashValue
let s3 = std.u32string("something")
let h3 = s3.hashValue
expectEqual(h1, h3)
expectNotEqual(h0, h1)
expectNotEqual(h0, h2)
expectNotEqual(h0, h3)
expectNotEqual(h1, h2)
expectNotEqual(h2, h3)
}
StdStringTestSuite.test("std::u16string <=> Swift.String") {
let cxx1 = std.u16string()
let swift1 = String(cxx1)
expectEqual(swift1, "")
let cxx2 = std.u16string("something123")
expectEqual(cxx2.size(), 12)
let swift2 = String(cxx2)
expectEqual(swift2, "something123")
let cxx3: std.u16string = "literal"
expectEqual(cxx3.size(), 7)
let cxx4: std.u16string = "тест"
expectEqual(cxx4.size(), 4)
let swift4 = String(cxx4)
expectEqual(swift4, "тест")
// Emojis are represented by more than one CWideChar.
let cxx5: std.u16string = "emoji_🤖"
expectEqual(cxx5.size(), 8)
let swift5 = String(cxx5)
expectEqual(swift5, "emoji_🤖")
let cxx6 = std.u16string("xyz\0abc")
expectEqual(cxx6.size(), 7)
let swift6 = String(cxx6)
expectEqual(swift6, "xyz\0abc")
let cxxLiteral: std.u16string = "Hello"
let cxx8: std.u16string = "\(cxxLiteral), World!"
expectEqual(cxx8.size(), 13)
let swift8 = String(cxx8)
expectEqual(swift8, "Hello, World!")
}
StdStringTestSuite.test("std::u32string <=> Swift.String") {
let cxx1 = std.u32string()
let swift1 = String(cxx1)
expectEqual(swift1, "")
let cxx2 = std.u32string("something123")
expectEqual(cxx2.size(), 12)
let swift2 = String(cxx2)
expectEqual(swift2, "something123")
let cxx3: std.u32string = "literal"
expectEqual(cxx3.size(), 7)
let cxx4: std.u32string = "тест"
expectEqual(cxx4.size(), 4)
let swift4 = String(cxx4)
expectEqual(swift4, "тест")
// Emojis are represented by more than one CWideChar.
let cxx5: std.u32string = "emoji_🤖"
expectEqual(cxx5.size(), 7)
let swift5 = String(cxx5)
expectEqual(swift5, "emoji_🤖")
let cxx6 = std.u32string("xyz\0abc")
expectEqual(cxx6.size(), 7)
let swift6 = String(cxx6)
expectEqual(swift6, "xyz\0abc")
let cxxLiteral: std.u32string = "Hello"
let cxx8: std.u32string = "\(cxxLiteral), World!"
expectEqual(cxx8.size(), 13)
let swift8 = String(cxx8)
expectEqual(swift8, "Hello, World!")
}
StdStringTestSuite.test("std::string as Swift.CustomDebugStringConvertible") {
let cxx1 = std.string()
expectEqual(cxx1.debugDescription, "std.string()")
let cxx2 = std.string("something123")
expectEqual(cxx2.debugDescription, "std.string(something123)")
let bytes: [UInt8] = [0xE1, 0xC1, 0xAC]
var cxx3 = std.string()
for byte in bytes {
cxx3.push_back(CChar(bitPattern: byte))
}
expectEqual(cxx3.debugDescription, "std.string(<28><><EFBFBD>)")
}
StdStringTestSuite.test("std::u16string as Swift.CustomDebugStringConvertible") {
let cxx1 = std.u16string()
expectEqual(cxx1.debugDescription, "std.u16string()")
let cxx2 = std.u16string("something123")
expectEqual(cxx2.debugDescription, "std.u16string(something123)")
let scalars: [UInt16] = [97, 55296, 99]
var cxx3 = std.u16string()
for scalar in scalars {
cxx3.push_back(scalar)
}
expectEqual(cxx3.debugDescription, "std.u16string(a<>c)")
}
StdStringTestSuite.test("std::u32string as Swift.CustomDebugStringConvertible") {
let cxx1 = std.u32string()
expectEqual(cxx1.debugDescription, "std.u32string()")
let cxx2 = std.u32string("something123")
expectEqual(cxx2.debugDescription, "std.u32string(something123)")
// Since std::u32string does not support pushing back UInt32 directly, we utilize UInt16 instead.
let scalars: [UInt16] = [97, 55296, 99]
var cxx3_16 = std.u16string()
for scalar: UInt16 in scalars {
cxx3_16.push_back(scalar)
}
let cxx3 = std.u32string(String(cxx3_16))
expectEqual(cxx3.debugDescription, "std.u32string(a<>c)")
}
StdStringTestSuite.test("std::string as Swift.Sequence") {
let cxx1 = std.string()
var iterated = false
for _ in cxx1 {
iterated = true
}
expectFalse(iterated)
let cxx2 = std.string("abc123")
var chars = 0
var sum = 0
for it in cxx2 {
chars += 1
sum += Int(it)
}
expectEqual(6, chars)
expectEqual(97 + 98 + 99 + 49 + 50 + 51, sum)
}
StdStringTestSuite.test("std::string as CustomStringConvertible") {
let cxx1 = std.string()
expectEqual(cxx1.description, "")
let cxx2 = std.string("something123")
expectEqual(cxx2.description, "something123")
let bytes: [UInt8] = [0xE1, 0xC1, 0xAC]
var cxx3 = std.string()
for byte in bytes {
cxx3.push_back(CChar(bitPattern: byte))
}
expectEqual(cxx3.description, "<EFBFBD><EFBFBD><EFBFBD>")
}
StdStringTestSuite.test("std::u16string as Swift.CustomStringConvertible") {
let cxx1 = std.u16string()
expectEqual(cxx1.description, "")
let cxx2 = std.u16string("something123")
expectEqual(cxx2.description, "something123")
let scalars: [UInt16] = [97, 55296, 99]
var cxx3 = std.u16string()
for scalar in scalars {
cxx3.push_back(scalar)
}
expectEqual(cxx3.description, "a<EFBFBD>c")
}
StdStringTestSuite.test("std::u32string as Swift.CustomStringConvertible") {
let cxx1 = std.u32string()
expectEqual(cxx1.description, "")
let cxx2 = std.u32string("something123")
expectEqual(cxx2.description, "something123")
// Since std::u32string does not support pushing back UInt32 directly, we utilize UInt16 instead.
let scalars: [UInt16] = [97, 55296, 99]
var cxx3_16 = std.u16string()
for scalar: UInt16 in scalars {
cxx3_16.push_back(scalar)
}
let cxx3 = std.u32string(String(cxx3_16))
expectEqual(cxx3.description, "a<EFBFBD>c")
// For `push_back`
let scalars2: [Unicode.Scalar] = [0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x2C, 0x20, 0x4E16, 0x754C]
.compactMap { Unicode.Scalar($0) }
var cxx4 = std.u32string()
for scalar: Unicode.Scalar in scalars2 {
cxx4.push_back(scalar)
}
expectEqual(cxx4.description, "Hello, 世界")
}
StdStringTestSuite.test("std::string from C string") {
let str = "abc".withCString { ptr in
std.string(ptr)
}
expectEqual(str, std.string("abc"))
}
#if USE_CUSTOM_STRING_API
StdStringTestSuite.test("get from a method") {
let box = HasMethodThatReturnsString()
let str = box.getString()
expectEqual(str.size(), 3)
expectEqual(str, std.string("111"))
}
StdStringTestSuite.test("pass as an argument") {
let s = std.string("a")
let res = takesStringWithDefaultArg(s)
expectEqual(res.size(), 1)
expectEqual(res[0], 97)
}
StdStringTestSuite.test("pass as a default argument") {
let res = takesStringWithDefaultArg()
expectEqual(res.size(), 3)
expectEqual(res[0], 97)
expectEqual(res[1], 98)
expectEqual(res[2], 99)
}
#endif
runAllTests()