diff --git a/Sources/SwiftASCII/ASCIICharacter.swift b/Sources/SwiftASCII/ASCIICharacter.swift index de68a5f..f97ce1d 100644 --- a/Sources/SwiftASCII/ASCIICharacter.swift +++ b/Sources/SwiftASCII/ASCIICharacter.swift @@ -9,7 +9,6 @@ import Foundation /// A type containing a `Character` instance that is guaranteed to conform to ASCII encoding. /// Offers a validating `exactly: Character` failable initializer and a `_ lossy: Character` conversion initializer. public struct ASCIICharacter: Hashable { - /// The ASCII character returned as a `Character` public let characterValue: Character @@ -18,28 +17,23 @@ public struct ASCIICharacter: Hashable { /// The ASCII character encoded as raw Data public var rawData: Data { - Data([asciiValue]) - } /// Returns a new `ASCIICharacter` instance if the source character is a valid ASCII character. @inlinable public init?(exactly source: Character) { - guard let getASCIIValue = source.asciiValue else { return nil } self.characterValue = source self.asciiValue = getASCIIValue - } /// Returns a new `ASCIICharacter` instance from the source character, converting a non-ASCII character to its closest ASCII equivalent if necessary. @inlinable public init(_ lossy: Character) { - guard let getASCIIValue = lossy.asciiValue else { // if ASCII encoding fails, fall back to a default character instead of throwing an exception @@ -54,14 +48,12 @@ public struct ASCIICharacter: Hashable { self.characterValue = lossy self.asciiValue = getASCIIValue - } /// Returns a new `ASCIICharacter` instance if the source string contains a single character and the character is a valid ASCII character. @_disfavoredOverload @inlinable - public init?(exactly source: String) { - + public init?(exactly source: S) { guard source.count == 1, let char = source.first else { return nil } @@ -72,24 +64,20 @@ public struct ASCIICharacter: Hashable { self.characterValue = char self.asciiValue = getASCIIValue - } /// Returns a new `ASCIICharacter` instance if the source string contains a single character, converting a non-ASCII character to its closest ASCII equivalent if necessary. @inlinable - public init(_ lossy: String) { - + public init(_ lossy: S) { let char: Character = lossy.first ?? "?" self.init(char) - } /// Returns a new `ASCIICharacter` instance if the source data is a single ASCII character. /// Returns `nil` if the source data is not a single byte or if it contains a non-ASCII character byte. @inlinable public init?(exactly source: Data) { - guard source.count == 1 else { return nil } guard let string = String(data: source, encoding: .nonLossyASCII) else { @@ -102,58 +90,43 @@ public struct ASCIICharacter: Hashable { self.characterValue = Character(scalar) self.asciiValue = UInt8(ascii: scalar) - } /// Returns a new `ASCIICharacter` instance from an ASCII character number. /// Returns `nil` if the number is not within the valid ASCII table (0..<128). @inlinable public init?(_ asciiValue: T) { - guard let getASCIIValue = UInt8(exactly: asciiValue) else { return nil } self.init(exactly: Data([getASCIIValue])) - } - } extension ASCIICharacter: ExpressibleByExtendedGraphemeClusterLiteral { - public typealias ExtendedGraphemeClusterLiteralType = Character public init(extendedGraphemeClusterLiteral value: Character) { - self.init(value) - } - } extension ASCIICharacter: CustomStringConvertible { - public var description: String { - // If not a printable character, return an empty string and don't allow any non-printable ASCII control characters through - (32...126).contains(asciiValue) + (32 ... 126).contains(asciiValue) ? String(characterValue) - : "" - + : "?" } - } extension ASCIICharacter: CustomDebugStringConvertible { - public var debugDescription: String { "ASCIICharacter(#\(asciiValue): \"" + description + "\")" } - } extension ASCIICharacter: Equatable { - // Self & Self public static func == (lhs: Self, rhs: Self) -> Bool { @@ -183,59 +156,45 @@ extension ASCIICharacter: Equatable { public static func != (lhs: Character, rhs: Self) -> Bool { lhs != rhs.characterValue } - } extension ASCIICharacter: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() let string = try container.decode(String.self) guard let newInstance = Self(exactly: string) else { throw DecodingError.dataCorrupted( - .init(codingPath: container.codingPath, - debugDescription: "Value was not valid ASCII character number.") + .init( + codingPath: container.codingPath, + debugDescription: "Value was not valid ASCII character number." + ) ) } self = newInstance - } public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() try container.encode(String(characterValue)) - } - } extension ASCIICharacter { - public static func + (lhs: ASCIICharacter, rhs: ASCIICharacter) -> ASCIIString { - ASCIIString([lhs, rhs]) - } public static func + (lhs: ASCIICharacter, rhs: ASCIIString) -> ASCIIString { - ASCIIString(lhs) + rhs - } public static func + (lhs: ASCIIString, rhs: ASCIICharacter) -> ASCIIString { - lhs + ASCIIString(rhs) - } - } extension ASCIICharacter { - /// Convenience: initialize a `ASCIICharacter` instance. public static func exactly(_ source: Character) -> ASCIICharacter? { Self(exactly: source) @@ -247,12 +206,12 @@ extension ASCIICharacter { } /// Convenience: initialize a `ASCIICharacter` instance. - public static func exactly(_ source: String) -> ASCIICharacter? { + public static func exactly(_ source: S) -> ASCIICharacter? { Self(exactly: source) } /// Convenience: initialize a `ASCIICharacter` instance. - public static func lossy(_ source: String) -> ASCIICharacter { + public static func lossy(_ source: S) -> ASCIICharacter { Self(source) } @@ -265,25 +224,25 @@ extension ASCIICharacter { public static func exactly(_ value: T) -> ASCIICharacter? { Self(value) } - } extension Sequence where Element == ASCIICharacter { - /// Returns a new string by concatenating the elements of the sequence. public func joined() -> ASCIIString { - ASCIIString(self) - } /// Returns a new string by concatenating the elements of the sequence, adding the given separator between each element. public func joined(separator: ASCIIString) -> ASCIIString { - - let joinedStr = map { "\($0.characterValue)" }.joined(separator: separator.stringValue) - let joinedData = Data(map { $0.rawData }.joined(separator: separator.rawData)) - return ASCIIString(guaranteedASCII: joinedStr, rawData: joinedData) - + let joinedStr = map { "\($0.characterValue)" } + .joined(separator: separator.stringValue) + let joinedData = Data( + map { $0.rawData } + .joined(separator: separator.rawData) + ) + return ASCIIString( + guaranteedASCII: joinedStr, + rawData: joinedData + ) } - } diff --git a/Sources/SwiftASCII/ASCIIString.swift b/Sources/SwiftASCII/ASCIIString.swift index 7202840..89f02f7 100644 --- a/Sources/SwiftASCII/ASCIIString.swift +++ b/Sources/SwiftASCII/ASCIIString.swift @@ -9,7 +9,6 @@ import Foundation /// A type containing a `String` instance that is guaranteed to conform to ASCII encoding. /// Offers a validating `exactly: String` failable initializer and a `_ lossy: String` conversion initializer. public struct ASCIIString: Hashable { - /// The ASCII string returned as a `String` public let stringValue: String @@ -19,38 +18,33 @@ public struct ASCIIString: Hashable { /// Returns a new `ASCIIString` instance if the source string is an ASCII string verbatim. /// Returns `nil` if the source string contains any non-ASCII characters. @inlinable - public init?(exactly source: String) { - + public init?(exactly source: S) { guard source.allSatisfy({ $0.isASCII }), let asciiData = source.data(using: .ascii) else { return nil } - self.stringValue = source + self.stringValue = String(source) self.rawData = asciiData - } /// Returns a new `ASCIIString` instance if the source data contains an ASCII string verbatim. /// Returns `nil` if the source data contains any non-ASCII character bytes. @inlinable public init?(exactly source: Data) { - guard let string = String(data: source, encoding: .nonLossyASCII), string.allSatisfy({ $0.isASCII }) else { return nil } self.stringValue = string self.rawData = source - } /// Returns a new `ASCIIString` instance from the source string, removing or converting any non-ASCII characters if necessary. @inlinable - public init(_ lossy: String) { - + public init(_ lossy: S) { guard lossy.allSatisfy({ $0.isASCII }), - let asciiData = lossy.data(using: .ascii) else { - + let asciiData = lossy.data(using: .ascii) + else { // if ASCII encoding fails, fall back to a default string instead of throwing an exception self.stringValue = lossy.asciiStringLossy.stringValue @@ -58,77 +52,62 @@ public struct ASCIIString: Hashable { return } - self.stringValue = lossy + self.stringValue = String(lossy) self.rawData = asciiData - } /// Returns a new `ASCIIString` instance from a `ASCIICharacter` sequence. @inlinable - public init(_ characters: S) where S : Sequence, S.Element == ASCIICharacter { - + public init(_ characters: S) + where S: Sequence, S.Element == ASCIICharacter + { self.stringValue = String(characters.map { $0.characterValue }) self.rawData = Data(characters.map { $0.asciiValue }) - } /// Returns a new `ASCIIString` instance by concatenating a `ASCIIString` sequence. @inlinable - public init(_ substrings: S) where S : Sequence, S.Element == ASCIIString { - + public init(_ substrings: S) + where S: Sequence, S.Element == ASCIIString + { self.stringValue = substrings.map { $0.stringValue }.joined() self.rawData = Data(substrings.map { $0.rawData }.joined()) - } /// Returns a new `ASCIIString` instance from an `ASCIICharacter`. @inlinable public init(_ character: ASCIICharacter) { - self.stringValue = "\(character.characterValue)" self.rawData = character.rawData - } - } extension ASCIIString: ExpressibleByStringLiteral { - public typealias StringLiteralType = String @inlinable public init(stringLiteral: String) { - self.init(stringLiteral) - } - } extension ASCIIString: CustomStringConvertible { - public var description: String { stringValue } - } extension ASCIIString: CustomDebugStringConvertible { - public var debugDescription: String { "ASCIIString(\"\(stringValue)\")" } - } extension ASCIIString: LosslessStringConvertible { - // required init already implemented above - } extension ASCIIString: Equatable { - public static func == (lhs: Self, rhs: T) -> Bool { lhs.stringValue == rhs } @@ -144,48 +123,38 @@ extension ASCIIString: Equatable { public static func != (lhs: T, rhs: Self) -> Bool { lhs != rhs.stringValue } - } extension ASCIIString: Codable { - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() let stringValue = try container.decode(String.self) guard let newInstance = Self(exactly: stringValue) else { throw DecodingError.dataCorrupted( - .init(codingPath: container.codingPath, - debugDescription: "Encoded string is not a valid ASCII string.") + .init( + codingPath: container.codingPath, + debugDescription: "Encoded string is not a valid ASCII string." + ) ) } self = newInstance - } public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() try container.encode(stringValue) - } - } extension ASCIIString { - public static func + (lhs: ASCIIString, rhs: ASCIIString) -> ASCIIString { - ASCIIString([lhs, rhs]) - } - } extension ASCIIString { - /// Convenience: initialize a `ASCIIString` instance. - public static func exactly(_ source: String) -> ASCIIString? { + public static func exactly(_ source: S) -> ASCIIString? { Self(exactly: source) } @@ -195,45 +164,38 @@ extension ASCIIString { } /// Convenience: initialize a `ASCIIString` instance. - public static func lossy(_ source: String) -> ASCIIString { + public static func lossy(_ source: S) -> ASCIIString { Self(source) } - } extension Sequence where Element == ASCIIString { - /// Returns a new string by concatenating the elements of the sequence. public func joined() -> ASCIIString { - let joinedStr = map { $0.stringValue }.joined() let joinedData = Data(map { $0.rawData }.joined()) - return ASCIIString(guaranteedASCII: joinedStr, rawData: joinedData) - + return ASCIIString(guaranteedASCII: joinedStr, + rawData: joinedData) } /// Returns a new string by concatenating the elements of the sequence, adding the given separator between each element. public func joined(separator: ASCIIString) -> ASCIIString { - - let joinedStr = map { $0.stringValue }.joined(separator: separator.stringValue) - let joinedData = Data(map { $0.rawData }.joined(separator: separator.rawData)) - return ASCIIString(guaranteedASCII: joinedStr, rawData: joinedData) - + let joinedStr = map { $0.stringValue } + .joined(separator: separator.stringValue) + let joinedData = Data(map { $0.rawData } + .joined(separator: separator.rawData)) + return ASCIIString(guaranteedASCII: joinedStr, + rawData: joinedData) } - } // MARK: - Internal Utility extension ASCIIString { - /// Internal use only. /// Used when string and data are already known to be valid ASCII. internal init(guaranteedASCII string: String, rawData: Data) { - self.stringValue = string self.rawData = rawData - } - } diff --git a/Sources/SwiftASCII/CharacterSet.swift b/Sources/SwiftASCII/CharacterSet.swift index ad68001..da6bf9d 100644 --- a/Sources/SwiftASCII/CharacterSet.swift +++ b/Sources/SwiftASCII/CharacterSet.swift @@ -6,30 +6,28 @@ import Foundation extension CharacterSet { - /// Includes all ASCII characters, including printable and non-printable (0...127) internal static let ascii = CharacterSet( - charactersIn: UnicodeScalar(0)...UnicodeScalar(127) + charactersIn: UnicodeScalar(0) ... UnicodeScalar(127) ) /// Includes all printable ASCII characters (32...126) internal static let asciiPrintable = CharacterSet( - charactersIn: UnicodeScalar(32)...UnicodeScalar(126) + charactersIn: UnicodeScalar(32) ... UnicodeScalar(126) ) /// Includes all ASCII characters, including printable and non-printable (0...31) internal static let asciiNonPrintable = CharacterSet( - charactersIn: UnicodeScalar(0)...UnicodeScalar(31) + charactersIn: UnicodeScalar(0) ... UnicodeScalar(31) ) /// Includes all extended ASCII characters (128...255) internal static let asciiExtended = CharacterSet( - charactersIn: UnicodeScalar(128)...UnicodeScalar(255) + charactersIn: UnicodeScalar(128) ... UnicodeScalar(255) ) /// Includes all ASCII characters and extended characters (0...255) internal static let asciiFull = CharacterSet( - charactersIn: UnicodeScalar(0)...UnicodeScalar(255) + charactersIn: UnicodeScalar(0) ... UnicodeScalar(255) ) - } diff --git a/Sources/SwiftASCII/String.swift b/Sources/SwiftASCII/String.swift index f37e9a8..36873dd 100644 --- a/Sources/SwiftASCII/String.swift +++ b/Sources/SwiftASCII/String.swift @@ -5,26 +5,35 @@ import Foundation -extension String { - +// MARK: - Inits + +extension StringProtocol where Self == String { /// Initialize from an `ASCIIString` instance. @inlinable public init(_ asciiString: ASCIIString) { - self = asciiString.stringValue - } - - /// Converts a String to `ASCIIString` exactly. +} + +extension StringProtocol { + /// Initialize from an `ASCIIString` instance. + @inlinable + public init(_ asciiString: ASCIIString) { + self = Self(stringLiteral: asciiString.stringValue) + } +} + +// MARK: - Category Methods + +extension StringProtocol { + /// Converts a string to `ASCIIString` exactly. /// Returns `nil` if `self` is not encodable as ASCII. @inlinable public var asciiString: ASCIIString? { - ASCIIString(exactly: self) - } - /// Converts a String to `ASCIIString` lossily. + /// Converts a `String` to `ASCIIString` lossily. /// /// Performs a lossy conversion, transforming characters to printable ASCII substitutions where necessary. /// @@ -33,44 +42,16 @@ extension String { /// Where a suitable character substitution can't reasonably be performed, a question-mark "?" will be substituted. @available(OSX 10.11, iOS 9.0, *) public var asciiStringLossy: ASCIIString { - let transformed = self - .applyingTransform(StringTransform("Latin-ASCII"), - reverse: false) + .applyingTransform( + StringTransform("Latin-ASCII"), + reverse: false + ) - let components = (transformed ?? Self(self)) + let components = (transformed ?? String(self)) .components(separatedBy: CharacterSet.asciiPrintable.inverted) return ASCIIString(exactly: components.joined(separator: "?")) ?? ASCIIString("") - - } - -} - -extension Substring { - - /// Converts a String to `ASCIIString` exactly. - /// Returns nil if `self` is not encodable as ASCII. - @inlinable - public var asciiString: ASCIIString? { - - ASCIIString(exactly: String(self)) - - } - - /// Converts a String to `ASCIIString` lossily. - /// - /// Performs a lossy conversion, transforming characters to printable ASCII substitutions where necessary. - /// - /// Note that some characters may be transformed to representations that occupy more than one ASCII character. For example: char 189 (½) will be converted to "1/2" - /// - /// Where a suitable character substitution can't reasonably be performed, a question-mark "?" will be substituted. - @available(OSX 10.11, iOS 9.0, *) - public var asciiStringLossy: ASCIIString { - - String(self).asciiStringLossy - } - } diff --git a/Tests/SwiftASCIITests/ASCIICharacter Tests.swift b/Tests/SwiftASCIITests/ASCIICharacter Tests.swift index e2c03c4..3b6b2df 100644 --- a/Tests/SwiftASCIITests/ASCIICharacter Tests.swift +++ b/Tests/SwiftASCIITests/ASCIICharacter Tests.swift @@ -9,12 +9,10 @@ import XCTest import SwiftASCII class ASCIICharacterTests: XCTestCase { - override func setUp() { super.setUp() } override func tearDown() { super.tearDown() } func testInit_exactly_Character() { - // init(exactly: Character) XCTAssertEqual(ASCIICharacter(exactly: Character("A"))?.characterValue, "A") @@ -22,20 +20,15 @@ class ASCIICharacterTests: XCTestCase { XCTAssertNil(ASCIICharacter(exactly: "😃")) XCTAssertNil(ASCIICharacter(exactly: "Ä")) - } func testInit_exactly_String() { - - // init(exactly: String) + // init(exactly: StringProtocol) XCTAssertNil(ASCIICharacter(exactly: "A string")) - - } func testInit_exactly_Data() { - // init(BinaryInteger) XCTAssertEqual(ASCIICharacter(exactly: Data([65])), "A") @@ -45,11 +38,9 @@ class ASCIICharacterTests: XCTestCase { // non-ASCII char numbers XCTAssertNil(ASCIICharacter(exactly: Data([128]))) // extended ASCII - } func testInit_BinaryInteger() { - // init(BinaryInteger) XCTAssertEqual(ASCIICharacter(65), "A") @@ -60,11 +51,9 @@ class ASCIICharacterTests: XCTestCase { // non-ASCII char numbers XCTAssertNil(ASCIICharacter(128)) // extended ASCII XCTAssertNil(ASCIICharacter(300)) // out of bounds - } func testasciiValue() { - XCTAssertEqual(ASCIICharacter(65)?.asciiValue, 65) // non-printable ASCII chars @@ -73,11 +62,9 @@ class ASCIICharacterTests: XCTestCase { // non-ASCII char numbers XCTAssertNil(ASCIICharacter(128)?.asciiValue) // extended ASCII XCTAssertNil(ASCIICharacter(300)?.asciiValue) // out of bounds - } func testRawData() { - XCTAssertEqual(ASCIICharacter(65)?.rawData, Data([65])) // non-printable ASCII chars @@ -86,31 +73,29 @@ class ASCIICharacterTests: XCTestCase { // non-ASCII char numbers XCTAssertNil(ASCIICharacter(128)?.rawData) // extended ASCII XCTAssertNil(ASCIICharacter(300)?.rawData) // out of bounds - } func testCustomStringConvertible() { - XCTAssertEqual(String(describing: ASCIICharacter(65)!), "A") // non-printable ASCII chars - XCTAssertEqual(String(describing: ASCIICharacter(0)!), "") - + XCTAssertEqual(String(describing: ASCIICharacter(0)!), "?") } func testCustomDebugStringConvertible() { - - XCTAssertEqual(ASCIICharacter(65)!.debugDescription, - #"ASCIICharacter(#65: "A")"#) + XCTAssertEqual( + ASCIICharacter(65)!.debugDescription, + #"ASCIICharacter(#65: "A")"# + ) // non-printable ASCII chars - XCTAssertEqual(ASCIICharacter(0)!.debugDescription, - #"ASCIICharacter(#0: "")"#) - + XCTAssertEqual( + ASCIICharacter(0)!.debugDescription, + #"ASCIICharacter(#0: "?")"# + ) } func testEquatable() { - // Self & Self XCTAssertTrue(ASCIICharacter("A") == ASCIICharacter("A")) @@ -126,11 +111,9 @@ class ASCIICharacterTests: XCTestCase { XCTAssertTrue(Character("A") == ASCIICharacter("A")) XCTAssertFalse(Character("A") != ASCIICharacter("A")) - } func testCodable() throws { - let encoder = JSONEncoder() let decoder = JSONDecoder() @@ -140,48 +123,52 @@ class ASCIICharacterTests: XCTestCase { let decoded = try decoder.decode(ASCIICharacter.self, from: encoded) XCTAssertEqual(str, decoded) - } func testStaticInits() { - let str: ASCIICharacter = .lossy("😃") XCTAssertEqual(str.characterValue, Character("?")) - let _: [ASCIICharacter] = [.lossy("A"), - .lossy("A string"), - .lossy(Character("A")), - .exactly(Character("A"))!, - .exactly("A")!, - .exactly(Data([65]))!, - .exactly(65)!] - - let _: [ASCIICharacter?] = [.lossy("A"), - .lossy("A string"), - .lossy(Character("A")), - .exactly(Character("A")), - .exactly("A"), - .exactly(Data([65])), - .exactly(65)] - + let _: [ASCIICharacter] = [ + .lossy("A"), + .lossy("A string"), + .lossy(Character("A")), + .exactly(Character("A"))!, + .exactly("A")!, + .exactly(Data([65]))!, + .exactly(65)! + ] + + let _: [ASCIICharacter?] = [ + .lossy("A"), + .lossy("A string"), + .lossy(Character("A")), + .exactly(Character("A")), + .exactly("A"), + .exactly(Data([65])), + .exactly(65) + ] } func testInterpolation() { + XCTAssertEqual( + ASCIICharacter("A") + ASCIICharacter("B"), + ASCIIString("AB") + ) - XCTAssertEqual(ASCIICharacter("A") + ASCIICharacter("B"), - ASCIIString("AB")) - - XCTAssertEqual(ASCIICharacter("A") + ASCIIString("BC"), - ASCIIString("ABC")) - - XCTAssertEqual(ASCIIString("AB") + ASCIICharacter("C"), - ASCIIString("ABC")) + XCTAssertEqual( + ASCIICharacter("A") + ASCIIString("BC"), + ASCIIString("ABC") + ) + XCTAssertEqual( + ASCIIString("AB") + ASCIICharacter("C"), + ASCIIString("ABC") + ) } func testJoined() { - XCTAssertEqual( [ASCIICharacter("A"), ASCIICharacter("B")].joined(), ASCIIString("AB") @@ -196,9 +183,7 @@ class ASCIICharacterTests: XCTestCase { [ASCIICharacter("A"), ASCIICharacter("B")].joined(separator: "123"), ASCIIString("A123B") ) - } - } #endif diff --git a/Tests/SwiftASCIITests/ASCIIString Tests.swift b/Tests/SwiftASCIITests/ASCIIString Tests.swift index e6ed989..595e99c 100644 --- a/Tests/SwiftASCIITests/ASCIIString Tests.swift +++ b/Tests/SwiftASCIITests/ASCIIString Tests.swift @@ -9,22 +9,18 @@ import XCTest import SwiftASCII class ASCIIStringTests: XCTestCase { - override func setUp() { super.setUp() } override func tearDown() { super.tearDown() } func testInit_exactly() { - // init(exactly:) XCTAssertEqual(ASCIIString(exactly: "A string")!.stringValue, "A string" as String) XCTAssertNil(ASCIIString(exactly: "Emöji 😃")) XCTAssertNil(ASCIIString(exactly: "😃")) - } func testInit_data() { - // init(data:) XCTAssertEqual(ASCIIString(exactly: Data())!.stringValue, "" as String) @@ -32,19 +28,15 @@ class ASCIIStringTests: XCTestCase { // ASCII only, reject extended ASCII (128...255) XCTAssertNotEqual(ASCIIString(exactly: Data([132]))?.stringValue, "ä" as String) - } func testCustomStringConvertible() { - XCTAssertEqual("\(ASCIIString(""))", "" as String) XCTAssertEqual("\(ASCIIString("A string"))", "A string" as String) XCTAssertEqual("\(ASCIIString("Emöji 😃"))", "Emoji ?" as String) - } func testInit_StringVariable() { - let str1 = "" XCTAssertEqual(ASCIIString(str1).stringValue, "" as String) @@ -53,34 +45,34 @@ class ASCIIStringTests: XCTestCase { let str3 = "Emöji 😃" XCTAssertEqual(ASCIIString(str3).stringValue, "Emoji ?" as String) - } func testInit_stringLiteral() { - // init(stringLiteral:) XCTAssertEqual(ASCIIString("").stringValue, "" as String) XCTAssertEqual(ASCIIString("A string").stringValue, "A string" as String) XCTAssertEqual(ASCIIString("Emöji 😃").stringValue, "Emoji ?" as String) - } func testCustomDebugStringConvertible() { + XCTAssertEqual( + ASCIIString("").debugDescription, + #"ASCIIString("")"# as String + ) - XCTAssertEqual(ASCIIString("").debugDescription, - #"ASCIIString("")"# as String) - - XCTAssertEqual(ASCIIString("A string").debugDescription, - #"ASCIIString("A string")"# as String) - - XCTAssertEqual(ASCIIString("Emöji 😃").debugDescription, - #"ASCIIString("Emoji ?")"# as String) + XCTAssertEqual( + ASCIIString("A string").debugDescription, + #"ASCIIString("A string")"# as String + ) + XCTAssertEqual( + ASCIIString("Emöji 😃").debugDescription, + #"ASCIIString("Emoji ?")"# as String + ) } func testEquatable() { - // Self & Self XCTAssertTrue(ASCIIString("A string") == ASCIIString("A string")) @@ -93,11 +85,9 @@ class ASCIIStringTests: XCTestCase { XCTAssertTrue("A string" as String == ASCIIString("A string")) XCTAssertFalse("A string" as String != ASCIIString("A string")) - } func testCodable() throws { - let encoder = JSONEncoder() let decoder = JSONDecoder() @@ -107,34 +97,34 @@ class ASCIIStringTests: XCTestCase { let decoded = try decoder.decode(ASCIIString.self, from: encoded) XCTAssertEqual(str, decoded) - } func testStaticInits() { - let str: ASCIIString = .lossy("Emöji 😃") XCTAssertEqual(str.stringValue, "Emoji ?" as String) - let _: [ASCIIString] = [.lossy("A string"), - .exactly("")!, - .exactly(Data([65]))!] - - let _: [ASCIIString?] = [.lossy("A string"), - .exactly(""), - .exactly(Data([65]))] - + let _: [ASCIIString] = [ + .lossy("A string"), + .exactly("")!, + .exactly(Data([65]))! + ] + + let _: [ASCIIString?] = [ + .lossy("A string"), + .exactly(""), + .exactly(Data([65])) + ] } func testInterpolation() { - - XCTAssertEqual(ASCIIString("AB") + ASCIIString("CD"), - ASCIIString("ABCD")) - + XCTAssertEqual( + ASCIIString("AB") + ASCIIString("CD"), + ASCIIString("ABCD") + ) } func testJoined() { - XCTAssertEqual( [ASCIIString("AB"), ASCIIString("CD")].joined(), ASCIIString("ABCD") @@ -149,9 +139,7 @@ class ASCIIStringTests: XCTestCase { [ASCIIString("AB"), ASCIIString("CD")].joined(separator: "123"), ASCIIString("AB123CD") ) - } - } #endif diff --git a/Tests/SwiftASCIITests/String Tests.swift b/Tests/SwiftASCIITests/String Tests.swift index 7716cc2..383bce1 100644 --- a/Tests/SwiftASCIITests/String Tests.swift +++ b/Tests/SwiftASCIITests/String Tests.swift @@ -9,47 +9,50 @@ import XCTest import SwiftASCII class StringTests: XCTestCase { - override func setUp() { super.setUp() } override func tearDown() { super.tearDown() } func testString_init_asciiString() { - - XCTAssertEqual(String(ASCIIString("An ASCII String.")), - "An ASCII String.") - + XCTAssertEqual( + String(ASCIIString("An ASCII String.")), + "An ASCII String." + ) + + XCTAssertEqual( + Substring(ASCIIString("An ASCII String.")), + "An ASCII String." + ) } func testString_asciiString() { - // String - XCTAssertEqual("An ASCII String.".asciiString?.stringValue, - "An ASCII String.") + XCTAssertEqual( + "An ASCII String.".asciiString?.stringValue, + "An ASCII String." + ) XCTAssertNil("Ãñ ÂŚÇÏÎ Strïńg.".asciiString) // Substring - XCTAssertEqual(Substring("An ASCII String.").asciiString?.stringValue, - "An ASCII String.") + XCTAssertEqual( + Substring("An ASCII String.").asciiString?.stringValue, + "An ASCII String." + ) XCTAssertNil(Substring("Ãñ ÂŚÇÏÎ Strïńg.").asciiString) - } func testString_asciiStringLossy() { - // printable ASCII chars - ensure they are kept intact and not translated - for charNum in 32...126 { - + for charNum in 32 ... 126 { let scalar = UnicodeScalar(charNum)! let string = String(scalar) XCTAssertEqual(string.asciiStringLossy.stringValue, string) - } // extended chars @@ -65,18 +68,40 @@ class StringTests: XCTestCase { // test context - XCTAssertEqual("The long brown dog walked lazily around the short xenophobic zebra" - .asciiStringLossy.stringValue, - "The long brown dog walked lazily around the short xenophobic zebra") + XCTAssertEqual( + "The long brown dog walked lazily around the short xenophobic zebra" + .asciiStringLossy.stringValue, + "The long brown dog walked lazily around the short xenophobic zebra" + ) - XCTAssertEqual("Le long 🐕 chien brun se promenait paresseusement autour du petit zèbre xénophobe" - .asciiStringLossy.stringValue, - "Le long ? chien brun se promenait paresseusement autour du petit zebre xenophobe") + XCTAssertEqual( + "Le long 🐕 chien brun se promenait paresseusement autour du petit zèbre xénophobe" + .asciiStringLossy.stringValue, + "Le long ? chien brun se promenait paresseusement autour du petit zebre xenophobe" + ) + // StringProtocol + func testSPL(_ s: S) -> ASCIIString { + s.asciiStringLossy + } + XCTAssertEqual(testSPL("Á"), "A") + + func testSP(_ s: S) -> ASCIIString? { + s.asciiString + } + XCTAssertEqual(testSP("A"), "A") + XCTAssertEqual(testSP("Á"), nil) + + func testSPInit(_ asciiString: ASCIIString, as strType: S.Type) -> S? { + S(asciiString) + } + + let str1: String? = testSPInit("A", as: String.self) + XCTAssertEqual(str1, "A") + let str2: Substring? = testSPInit("A", as: Substring.self) + XCTAssertEqual(str2, "A") } - } #endif -