// RUN: %empty-directory(%t) // RUN: %target-build-swift %s -o %t/a.out4 -swift-version 4 && %target-codesign %t/a.out4 && %target-run %t/a.out4 // Requires swift-version 4 // UNSUPPORTED: swift_test_mode_optimize_none_with_implicit_dynamic // REQUIRES: executable_test import StdlibUnittest //===--- MyString ---------------------------------------------------------===// /// A simple StringProtocol with a wacky .description that proves /// LosslessStringConvertible is not infecting ordinary constructions by using /// .description as the content of a copied string. struct MyString { var base: String } extension MyString : BidirectionalCollection { typealias Iterator = String.Iterator typealias Index = String.Index typealias SubSequence = MyString func makeIterator() -> Iterator { return base.makeIterator() } var startIndex: String.Index { return base.startIndex } var endIndex: String.Index { return base.startIndex } subscript(i: Index) -> Character { return base[i] } subscript(indices: Range) -> MyString { return MyString(base: String(self.base[indices])) } func index(after i: Index) -> Index { return base.index(after: i) } func index(before i: Index) -> Index { return base.index(before: i) } func index(_ i: Index, offsetBy n: Int) -> Index { return base.index(i, offsetBy: n) } func distance(from i: Index, to j: Index) -> Int { return base.distance(from: i, to: j) } } extension MyString : RangeReplaceableCollection { init() { base = "" } mutating func append(contentsOf s: S) where S.Element == Character { base.append(contentsOf: s) } mutating func replaceSubrange(_ r: Range, with c: C) where C.Element == Character { base.replaceSubrange(r, with: c) } } extension MyString : CustomStringConvertible { var description: String { return "***MyString***" } } extension MyString : TextOutputStream { public mutating func write(_ other: String) { append(contentsOf: other) } } extension MyString : TextOutputStreamable { public func write(to target: inout Target) { target.write(base) } } extension MyString : ExpressibleByUnicodeScalarLiteral { public init(unicodeScalarLiteral value: String) { base = .init(unicodeScalarLiteral: value) } } extension MyString : ExpressibleByExtendedGraphemeClusterLiteral { public init(extendedGraphemeClusterLiteral value: String) { base = .init(extendedGraphemeClusterLiteral: value) } } extension MyString : ExpressibleByStringLiteral { public init(stringLiteral value: String) { base = .init(stringLiteral: value) } } extension MyString : CustomReflectable { public var customMirror: Mirror { return base.customMirror } } extension MyString : CustomPlaygroundQuickLookable { public var customPlaygroundQuickLook: PlaygroundQuickLook { return base.customPlaygroundQuickLook } } extension MyString : CustomDebugStringConvertible { public var debugDescription: String { return "(***MyString***)" } } extension MyString : Equatable { public static func ==(lhs: MyString, rhs: MyString) -> Bool { return lhs.base == rhs.base } } extension MyString : Comparable { public static func <(lhs: MyString, rhs: MyString) -> Bool { return lhs.base < rhs.base } } extension MyString : Hashable { public var hashValue : Int { return base.hashValue } } extension MyString { public func hasPrefix(_ prefix: String) -> Bool { return self.base.hasPrefix(prefix) } public func hasSuffix(_ suffix: String) -> Bool { return self.base.hasSuffix(suffix) } } extension MyString : StringProtocol { var utf8: String.UTF8View { return base.utf8 } var utf16: String.UTF16View { return base.utf16 } var unicodeScalars: String.UnicodeScalarView { return base.unicodeScalars } var characters: String.CharacterView { return base.characters } func lowercased() -> String { return base.lowercased() } func uppercased() -> String { return base.uppercased() } init( decoding codeUnits: C, as sourceEncoding: Encoding.Type ) where C.Iterator.Element == Encoding.CodeUnit { base = .init(decoding: codeUnits, as: sourceEncoding) } init(cString nullTerminatedUTF8: UnsafePointer) { base = .init(cString: nullTerminatedUTF8) } init( decodingCString nullTerminatedCodeUnits: UnsafePointer, as sourceEncoding: Encoding.Type) { base = .init(decodingCString: nullTerminatedCodeUnits, as: sourceEncoding) } func withCString( _ body: (UnsafePointer) throws -> Result) rethrows -> Result { return try base.withCString(body) } func withCString( encodedAs targetEncoding: Encoding.Type, _ body: (UnsafePointer) throws -> Result ) rethrows -> Result { return try base.withCString(encodedAs: targetEncoding, body) } } //===----------------------------------------------------------------------===// public typealias ExpectedConcreteSlice = Substring public typealias ExpectedStringFromString = String let swift = 4 var Tests = TestSuite("StringCompatibility") Tests.test("String/Range/Slice/ExpectedType/\(swift)") { var s = "hello world" var sub = s[s.startIndex ..< s.endIndex] var subsub = sub[s.startIndex ..< s.endIndex] expectType(String.self, &s) expectType(ExpectedConcreteSlice.self, &sub) expectType(ExpectedConcreteSlice.self, &subsub) } Tests.test("String/ClosedRange/Slice/ExpectedType/\(swift)") { var s = "hello world" let lastIndex = s.index(before:s.endIndex) var sub = s[s.startIndex ... lastIndex] var subsub = sub[s.startIndex ... lastIndex] expectType(String.self, &s) expectType(ExpectedConcreteSlice.self, &sub) expectType(ExpectedConcreteSlice.self, &subsub) } Tests.test("Substring/Range/Slice/ExpectedType/\(swift)") { let s = "hello world" as Substring var sub = s[s.startIndex ..< s.endIndex] var subsub = sub[s.startIndex ..< s.endIndex] // slicing a String in Swift 3 produces a String // but slicing a Substring should still produce a Substring expectType(Substring.self, &sub) expectType(Substring.self, &subsub) } Tests.test("Substring/ClosedRange/Slice/ExpectedType/\(swift)") { let s = "hello world" as Substring let lastIndex = s.index(before:s.endIndex) var sub = s[s.startIndex ... lastIndex] var subsub = sub[s.startIndex ... lastIndex] expectType(ExpectedConcreteSlice.self, &sub) expectType(ExpectedConcreteSlice.self, &subsub) } Tests.test("RangeReplaceable.init/generic/\(swift)") { func check< T: RangeReplaceableCollection, S: Collection >(_: T.Type, from source: S) where T.Element : Equatable, T.Element == S.Element { var r = T(source) expectType(T.self, &r) expectEqualSequence(Array(source), Array(r)) } check(String.self, from: "a" as String) check(Substring.self, from: "b" as String) // FIXME: Why isn't this working? // check(MyString.self, from: "c" as String) check(String.self, from: "d" as Substring) check(Substring.self, from: "e" as Substring) // FIXME: Why isn't this working? // check(MyString.self, from: "f" as Substring) // FIXME: Why isn't this working? // check(String.self, from: "g" as MyString) // check(Substring.self, from: "h" as MyString) check(MyString.self, from: "i" as MyString) } Tests.test("String.init(someString)/default type/\(swift)") { var s = String("" as String) expectType(ExpectedStringFromString.self, &s) } Tests.test("Substring.init(someString)/default type/\(swift)") { var s = Substring("" as Substring) expectType(Substring.self, &s) } Tests.test("LosslessStringConvertible/generic/\(swift)") { func f(_ x: T.Type) { _ = T("")! // unwrapping optional should work in generic context } f(String.self) } public typealias ExpectedUTF8ViewSlice = String.UTF8View.SubSequence Tests.test("UTF8ViewSlicing") { let s = "Hello, String.UTF8View slicing world!".utf8 var slice = s[s.startIndex..