Merge pull request #714 from ScottPetit/sr-3193-nscalendar
diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
index 11b9f03..a2e844a 100644
--- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
+++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
@@ -171,7 +171,7 @@
void (*startElementNs)(_CFXMLInterface ctx,
const unsigned char *localname,
const unsigned char *_Nullable prefix,
- const unsigned char *URI,
+ const unsigned char *_Nullable URI,
int nb_namespaces,
const unsigned char *_Nullable *_Nonnull namespaces,
int nb_attributes,
@@ -180,7 +180,7 @@
void (*endElementNs)(_CFXMLInterface ctx,
const unsigned char *localname,
const unsigned char *_Nullable prefix,
- const unsigned char *URI);
+ const unsigned char *_Nullable URI);
void (*characters)(_CFXMLInterface ctx,
const unsigned char *ch,
int len);
diff --git a/CoreFoundation/Locale.subproj/CFLocale.c b/CoreFoundation/Locale.subproj/CFLocale.c
index b502faf..69dda52 100644
--- a/CoreFoundation/Locale.subproj/CFLocale.c
+++ b/CoreFoundation/Locale.subproj/CFLocale.c
@@ -280,7 +280,12 @@
#if DEPLOYMENT_TARGET_MACOSX
+// Specify a default locale on Mac for Swift
+#if DEPLOYMENT_RUNTIME_SWIFT
+#define FALLBACK_LOCALE_NAME CFSTR("en_US")
+#else
#define FALLBACK_LOCALE_NAME CFSTR("")
+#endif /* DEPLOYMENT_RUNTIME_SWIFT */
#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
#define FALLBACK_LOCALE_NAME CFSTR("en_US")
#elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
diff --git a/Docs/Status.md b/Docs/Status.md
index 6c0eb68..e3b8d0b 100644
--- a/Docs/Status.md
+++ b/Docs/Status.md
@@ -53,10 +53,10 @@
| `URLProtectionSpace` | Unimplemented | None | |
| `URLProtocol` | Unimplemented | None | |
| `URLProtocolClient` | Unimplemented | None | |
- | `NSURLRequest` | Mostly Complete | Incomplete | `NSCoding` remains unimplemented |
- | `NSMutableURLRequest` | Mostly Complete | Incomplete | `NSCoding` remains unimplemented |
- | `URLResponse` | Mostly Complete | Incomplete | `NSCoding` remains unimplemented |
- | `NSHTTPURLResponse` | Mostly Complete | Substantial | `NSCoding` remains unimplemented |
+ | `NSURLRequest` | Mostly Complete | Incomplete | |
+ | `NSMutableURLRequest` | Mostly Complete | Incomplete | |
+ | `URLResponse` | Mostly Complete | Incomplete | |
+ | `NSHTTPURLResponse` | Mostly Complete | Substantial | |
| `NSURL` | Mostly Complete | Substantial | `NSCoding` with non-keyed-coding archivers, `checkResourceIsReachable()`, and resource values remain unimplemented |
| `NSURLQueryItem` | Mostly Complete | N/A | `NSCoding` remains unimplemented |
| `URLResourceKey` | Complete | N/A | |
diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj
old mode 100755
new mode 100644
diff --git a/Foundation/NSData.swift b/Foundation/NSData.swift
index 7c368a2..80a07fa 100644
--- a/Foundation/NSData.swift
+++ b/Foundation/NSData.swift
@@ -217,7 +217,12 @@
}
open var bytes: UnsafeRawPointer {
- return UnsafeRawPointer(CFDataGetBytePtr(_cfObject))
+ guard let bytePtr = CFDataGetBytePtr(_cfObject) else {
+ //This could occure on empty data being encoded.
+ //TODO: switch with nil when signature is fixed
+ return UnsafeRawPointer(bitPattern: 0xf00deadb0c0)! //would not result in 'nil unwrapped optional'
+ }
+ return UnsafeRawPointer(bytePtr)
}
diff --git a/Foundation/NSFileHandle.swift b/Foundation/NSFileHandle.swift
old mode 100755
new mode 100644
diff --git a/Foundation/NSHTTPCookie.swift b/Foundation/NSHTTPCookie.swift
index 7da3b6e..f78dd5d 100644
--- a/Foundation/NSHTTPCookie.swift
+++ b/Foundation/NSHTTPCookie.swift
@@ -593,6 +593,30 @@
open var portList: [NSNumber]? {
return _portList
}
+
+ open override var description: String {
+ var str = "<\(type(of: self)) "
+ str += "version:\(self._version) name:\"\(self._name)\" value:\"\(self._value)\" expiresDate:"
+ if let expires = self._expiresDate {
+ str += "\(expires)"
+ } else {
+ str += "nil"
+ }
+ str += " sessionOnly:\(self._sessionOnly) domain:\"\(self._domain)\" path:\"\(self._path)\" isSecure:\(self._secure) comment:"
+ if let comments = self._comment {
+ str += "\(comments)"
+ } else {
+ str += "nil"
+ }
+ str += " ports:{ "
+ if let ports = self._portList {
+ str += "\(NSArray(array: (ports)).componentsJoined(by: ","))"
+ } else {
+ str += "0"
+ }
+ str += " }>"
+ return str
+ }
}
//utils for cookie parsing
diff --git a/Foundation/NSJSONSerialization.swift b/Foundation/NSJSONSerialization.swift
index 48f53b1..cd4aed7 100644
--- a/Foundation/NSJSONSerialization.swift
+++ b/Foundation/NSJSONSerialization.swift
@@ -101,14 +101,13 @@
/* Generate JSON data from a Foundation object. If the object will not produce valid JSON then an exception will be thrown. Setting the NSJSONWritingPrettyPrinted option will generate JSON with whitespace designed to make the output more readable. If that option is not set, the most compact possible JSON will be generated. If an error occurs, the error parameter will be set and the return value will be nil. The resulting data is a encoded in UTF-8.
*/
internal class func _data(withJSONObject value: Any, options opt: WritingOptions, stream: Bool) throws -> Data {
- var result = Data()
+ var jsonStr = String()
var writer = JSONWriter(
pretty: opt.contains(.prettyPrinted),
writer: { (str: String?) in
if let str = str {
- let count = str.lengthOfBytes(using: .utf8)
- result.append(UnsafeRawPointer(str.cString(using: .utf8)!).bindMemory(to: UInt8.self, capacity: count), count: count)
+ jsonStr.append(str)
}
}
)
@@ -131,6 +130,14 @@
}
}
+ let count = jsonStr.lengthOfBytes(using: .utf8)
+ let bufferLength = count+1 // Allow space for null terminator
+ var utf8: [CChar] = Array<CChar>(repeating: 0, count: bufferLength)
+ if !jsonStr.getCString(&utf8, maxLength: bufferLength, encoding: .utf8) {
+ fatalError("Failed to generate a CString from a String")
+ }
+ let rawBytes = UnsafeRawPointer(UnsafePointer(utf8))
+ let result = Data(bytes: rawBytes.bindMemory(to: UInt8.self, capacity: count), count: count)
return result
}
open class func data(withJSONObject value: Any, options opt: WritingOptions = []) throws -> Data {
@@ -270,21 +277,21 @@
}
mutating func serializeJSON(_ obj: Any) throws {
-
- if let str = obj as? String {
+
+ switch (obj) {
+ case let str as String:
try serializeString(str)
- } else if let num = _SwiftValue.store(obj) as? NSNumber {
- try serializeNumber(num)
- } else if let array = obj as? Array<Any> {
+ case let boolValue as Bool:
+ serializeBool(boolValue)
+ case _ where _SwiftValue.store(obj) is NSNumber:
+ try serializeNumber(_SwiftValue.store(obj) as! NSNumber)
+ case let array as Array<Any>:
try serializeArray(array)
- } else if let dict = obj as? Dictionary<AnyHashable, Any> {
+ case let dict as Dictionary<AnyHashable, Any>:
try serializeDictionary(dict)
- } else if let null = obj as? NSNull {
+ case let null as NSNull:
try serializeNull(null)
- } else if let boolVal = obj as? Bool {
- try serializeNumber(NSNumber(value: boolVal))
- }
- else {
+ default:
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "Invalid object cannot be serialized"])
}
}
@@ -319,15 +326,26 @@
writer("\"")
}
+ func serializeBool(_ bool: Bool) {
+ switch bool {
+ case true:
+ writer("true")
+ case false:
+ writer("false")
+ }
+ }
+
mutating func serializeNumber(_ num: NSNumber) throws {
if num.doubleValue.isInfinite || num.doubleValue.isNaN {
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "Number cannot be infinity or NaN"])
}
- // Cannot detect type information (e.g. bool) as there is no objCType property on NSNumber in Swift
- // So, just print the number
-
- writer(_serializationString(for: num))
+ switch num._objCType {
+ case .Bool:
+ serializeBool(num.boolValue)
+ default:
+ writer(_serializationString(for: num))
+ }
}
mutating func serializeArray(_ array: [Any]) throws {
diff --git a/Foundation/NSNotification.swift b/Foundation/NSNotification.swift
old mode 100755
new mode 100644
diff --git a/Foundation/NSNumber.swift b/Foundation/NSNumber.swift
index 14bec84..5f75de8 100644
--- a/Foundation/NSNumber.swift
+++ b/Foundation/NSNumber.swift
@@ -200,7 +200,9 @@
// This layout MUST be the same as CFNumber so that they are bridgeable
private var _base = _CFInfo(typeID: CFNumberGetTypeID())
private var _pad: UInt64 = 0
-
+
+ internal let _objCType: _NSSimpleObjCType
+
internal var _cfObject: CFType {
return unsafeBitCast(self, to: CFType.self)
}
@@ -221,77 +223,95 @@
}
return false
}
+
+ open override var objCType: UnsafePointer<Int8> {
+ return UnsafePointer<Int8>(bitPattern: UInt(_objCType.rawValue.value))!
+ }
deinit {
_CFDeinit(self)
}
public init(value: Int8) {
+ _objCType = .Char
super.init()
_CFNumberInitInt8(_cfObject, value)
}
public init(value: UInt8) {
+ _objCType = .UChar
super.init()
_CFNumberInitUInt8(_cfObject, value)
}
public init(value: Int16) {
+ _objCType = .Short
super.init()
_CFNumberInitInt16(_cfObject, value)
}
public init(value: UInt16) {
+ _objCType = .UShort
super.init()
_CFNumberInitUInt16(_cfObject, value)
}
public init(value: Int32) {
+ _objCType = .Long
super.init()
_CFNumberInitInt32(_cfObject, value)
}
public init(value: UInt32) {
+ _objCType = .ULong
super.init()
_CFNumberInitUInt32(_cfObject, value)
}
public init(value: Int) {
+ _objCType = .Int
super.init()
_CFNumberInitInt(_cfObject, value)
}
public init(value: UInt) {
+ _objCType = .UInt
super.init()
_CFNumberInitUInt(_cfObject, value)
}
public init(value: Int64) {
+ _objCType = .LongLong
super.init()
_CFNumberInitInt64(_cfObject, value)
}
public init(value: UInt64) {
+ _objCType = .ULongLong
super.init()
_CFNumberInitUInt64(_cfObject, value)
}
public init(value: Float) {
+ _objCType = .Float
super.init()
_CFNumberInitFloat(_cfObject, value)
}
public init(value: Double) {
+ _objCType = .Double
super.init()
_CFNumberInitDouble(_cfObject, value)
}
public init(value: Bool) {
+ _objCType = .Bool
super.init()
_CFNumberInitBool(_cfObject, value)
}
override internal init() {
+ _objCType = .Undef
super.init()
}
diff --git a/Foundation/NSNumberFormatter.swift b/Foundation/NSNumberFormatter.swift
index d0cf61e..fe319d1 100644
--- a/Foundation/NSNumberFormatter.swift
+++ b/Foundation/NSNumberFormatter.swift
@@ -70,6 +70,9 @@
let obj = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale._cfObject, numberStyle)!
_setFormatterAttributes(obj)
+ if let format = _format {
+ CFNumberFormatterSetFormat(obj, format._cfObject)
+ }
_currentCfFormatter = obj
return obj
}
@@ -99,12 +102,13 @@
open func number(from string: String) -> NSNumber? {
var range = CFRange(location: 0, length: string.length)
let number = withUnsafeMutablePointer(to: &range) { (rangePointer: UnsafeMutablePointer<CFRange>) -> NSNumber? in
-
+
#if os(OSX) || os(iOS)
- let result = CFNumberFormatterCreateNumberFromString(kCFAllocatorSystemDefault, _cfFormatter, string._cfObject, rangePointer, CFNumberFormatterOptionFlags.parseIntegersOnly.rawValue)
+ let parseOption = allowsFloats ? 0 : CFNumberFormatterOptionFlags.parseIntegersOnly.rawValue
#else
- let result = CFNumberFormatterCreateNumberFromString(kCFAllocatorSystemDefault, _cfFormatter, string._cfObject, rangePointer, CFOptionFlags(kCFNumberFormatterParseIntegersOnly))
+ let parseOption = allowsFloats ? 0 : CFOptionFlags(kCFNumberFormatterParseIntegersOnly)
#endif
+ let result = CFNumberFormatterCreateNumberFromString(kCFAllocatorSystemDefault, _cfFormatter, string._cfObject, rangePointer, parseOption)
return result?._nsObject
}
@@ -157,7 +161,7 @@
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterPerMillSymbol, value: _percentSymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterInternationalCurrencySymbol, value: _internationalCurrencySymbol?._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterCurrencyGroupingSeparator, value: _currencyGroupingSeparator?._cfObject)
- _setFormatterAttribute(formatter, attributeName: kCFNumberFormatterIsLenient, value: kCFBooleanTrue)
+ _setFormatterAttribute(formatter, attributeName: kCFNumberFormatterIsLenient, value: _lenient._cfObject)
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterUseSignificantDigits, value: _usesSignificantDigits._cfObject)
if _usesSignificantDigits {
_setFormatterAttribute(formatter, attributeName: kCFNumberFormatterMinSignificantDigits, value: _minimumSignificantDigits._bridgeToObjectiveC()._cfObject)
@@ -182,7 +186,7 @@
switch newValue {
case .none, .ordinal, .spellOut:
_usesSignificantDigits = false
-
+
case .currency, .currencyPlural, .currencyISOCode, .currencyAccounting:
_usesSignificantDigits = false
_usesGroupingSeparator = true
@@ -838,10 +842,10 @@
//
- internal var _format: String = "#;0;#"
+ internal var _format: String?
open var format: String {
get {
- return _format
+ return _format ?? "#;0;#"
}
set {
_reset()
diff --git a/Foundation/NSPredicate.swift b/Foundation/NSPredicate.swift
index 083782b..3aada9c 100644
--- a/Foundation/NSPredicate.swift
+++ b/Foundation/NSPredicate.swift
@@ -15,8 +15,8 @@
private enum PredicateKind {
case boolean(Bool)
case block((Any?, [String : Any]?) -> Bool)
- // TODO: case for init(format:argumentArray:)
- // TODO: case for init(fromMetadataQueryString:)
+ case format(String)
+ case metadataQuery(String)
}
private let kind: PredicateKind
@@ -26,11 +26,33 @@
}
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ guard aDecoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ let encodedBool = aDecoder.decodeBool(forKey: "NS.boolean.value")
+ self.kind = .boolean(encodedBool)
+
+ super.init()
}
open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ guard aCoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ //TODO: store kind key for .boolean, .format, .metadataQuery
+
+ switch self.kind {
+ case .boolean(let value):
+ aCoder.encode(value, forKey: "NS.boolean.value")
+ case .block:
+ preconditionFailure("NSBlockPredicate cannot be encoded or decoded.")
+ case .format:
+ NSUnimplemented()
+ case .metadataQuery:
+ NSUnimplemented()
+ }
}
open override func copy() -> Any {
@@ -38,7 +60,38 @@
}
open func copy(with zone: NSZone? = nil) -> Any {
- NSUnimplemented()
+ switch self.kind {
+ case .boolean(let value):
+ return NSPredicate(value: value)
+ case .block(let block):
+ return NSPredicate(block: block)
+ case .format:
+ NSUnimplemented()
+ case .metadataQuery:
+ NSUnimplemented()
+ }
+ }
+
+ open override func isEqual(_ object: Any?) -> Bool {
+ if let other = object as? NSPredicate {
+ if other === self {
+ return true
+ } else {
+ switch (other.kind, self.kind) {
+ case (.boolean(let otherBool), .boolean(let selfBool)):
+ return otherBool == selfBool
+ case (.format, .format):
+ NSUnimplemented()
+ case (.metadataQuery, .metadataQuery):
+ NSUnimplemented()
+ default:
+ // NSBlockPredicate returns false even for copy
+ return false
+ }
+ }
+ }
+
+ return false
}
// Parse predicateFormat and return an appropriate predicate
@@ -58,7 +111,21 @@
super.init()
}
- open var predicateFormat: String { NSUnimplemented() } // returns the format string of the predicate
+ open var predicateFormat: String {
+ switch self.kind {
+ case .boolean(let value):
+ return value ? "TRUEPREDICATE" : "FALSEPREDICATE"
+ case .block:
+ // TODO: Bring NSBlockPredicate's predicateFormat to macOS's Foundation version
+ // let address = unsafeBitCast(block, to: Int.self)
+ // return String(format:"BLOCKPREDICATE(%2X)", address)
+ return "BLOCKPREDICATE"
+ case .format:
+ NSUnimplemented()
+ case .metadataQuery:
+ NSUnimplemented()
+ }
+ }
open func withSubstitutionVariables(_ variables: [String : Any]) -> Self { NSUnimplemented() } // substitute constant values for variables
@@ -76,6 +143,10 @@
return value
case let .block(block):
return block(object, bindings)
+ case .format:
+ NSUnimplemented()
+ case .metadataQuery:
+ NSUnimplemented()
}
} // single pass evaluation substituting variables from the bindings dictionary for any variable expressions encountered
diff --git a/Foundation/NSPropertyList.swift b/Foundation/NSPropertyList.swift
index 7ea248a..5141c42 100644
--- a/Foundation/NSPropertyList.swift
+++ b/Foundation/NSPropertyList.swift
@@ -44,10 +44,11 @@
#else
let fmt = CFPropertyListFormat(format.rawValue)
#endif
- return CFPropertyListIsValid(unsafeBitCast(_SwiftValue.store(plist), to: CFPropertyList.self), fmt)
+ let plistObj = _SwiftValue.store(plist)
+ return CFPropertyListIsValid(plistObj, fmt)
}
-
- open class func data(fromPropertyList plist: AnyObject, format: PropertyListFormat, options opt: WriteOptions) throws -> Data {
+
+ open class func data(fromPropertyList plist: Any, format: PropertyListFormat, options opt: WriteOptions) throws -> Data {
var error: Unmanaged<CFError>? = nil
let result = withUnsafeMutablePointer(to: &error) { (outErr: UnsafeMutablePointer<Unmanaged<CFError>?>) -> CFData? in
#if os(OSX) || os(iOS)
@@ -56,7 +57,8 @@
let fmt = CFPropertyListFormat(format.rawValue)
#endif
let options = CFOptionFlags(opt)
- return CFPropertyListCreateData(kCFAllocatorSystemDefault, plist, fmt, options, outErr)
+ let plistObj = _SwiftValue.store(plist)
+ return CFPropertyListCreateData(kCFAllocatorSystemDefault, plistObj, fmt, options, outErr)
}
if let res = result {
return res._swiftObject
@@ -64,7 +66,7 @@
throw error!.takeRetainedValue()._nsObject
}
}
-
+
/// - Experiment: Note that the return type of this function is different than on Darwin Foundation (Any instead of AnyObject). This is likely to change once we have a more complete story for bridging in place.
open class func propertyList(from data: Data, options opt: ReadOptions = [], format: UnsafeMutablePointer<PropertyListFormat>?) throws -> Any {
var fmt = kCFPropertyListBinaryFormat_v1_0
diff --git a/Foundation/NSURLRequest.swift b/Foundation/NSURLRequest.swift
index 7081e0f..a044297 100644
--- a/Foundation/NSURLRequest.swift
+++ b/Foundation/NSURLRequest.swift
@@ -156,11 +156,101 @@
}
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ guard aDecoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ if let encodedURL = aDecoder.decodeObject(forKey: "NS.url") as? NSURL {
+ self.url = encodedURL._swiftObject
+ }
+
+ if let encodedHeaders = aDecoder.decodeObject(forKey: "NS._allHTTPHeaderFields") as? NSDictionary {
+ self._allHTTPHeaderFields = encodedHeaders.reduce([String : String]()) { result, item in
+ var result = result
+ if let key = item.key as? NSString,
+ let value = item.value as? NSString {
+ result[key._swiftObject] = value._swiftObject
+ }
+ return result
+ }
+ }
+
+ if let encodedDocumentURL = aDecoder.decodeObject(forKey: "NS.mainDocumentURL") as? NSURL {
+ self.mainDocumentURL = encodedDocumentURL._swiftObject
+ }
+
+ if let encodedMethod = aDecoder.decodeObject(forKey: "NS.httpMethod") as? NSString {
+ self.httpMethod = encodedMethod._swiftObject
+ }
+
+ let encodedCachePolicy = aDecoder.decodeObject(forKey: "NS._cachePolicy") as! NSNumber
+ self._cachePolicy = CachePolicy(rawValue: encodedCachePolicy.uintValue)!
+
+ let encodedTimeout = aDecoder.decodeObject(forKey: "NS._timeoutInterval") as! NSNumber
+ self._timeoutInterval = encodedTimeout.doubleValue
+
+ let encodedHttpBody: Data? = aDecoder.withDecodedUnsafeBufferPointer(forKey: "NS.httpBody") {
+ guard let buffer = $0 else { return nil }
+ return Data(buffer: buffer)
+ }
+
+ if let encodedHttpBody = encodedHttpBody {
+ self._body = .data(encodedHttpBody)
+ }
+
+ let encodedNetworkServiceType = aDecoder.decodeObject(forKey: "NS._networkServiceType") as! NSNumber
+ self._networkServiceType = NetworkServiceType(rawValue: encodedNetworkServiceType.uintValue)!
+
+ let encodedCellularAccess = aDecoder.decodeObject(forKey: "NS._allowsCellularAccess") as! NSNumber
+ self._allowsCellularAccess = encodedCellularAccess.boolValue
+
+ let encodedHandleCookies = aDecoder.decodeObject(forKey: "NS._httpShouldHandleCookies") as! NSNumber
+ self._httpShouldHandleCookies = encodedHandleCookies.boolValue
+
+ let encodedUsePipelining = aDecoder.decodeObject(forKey: "NS._httpShouldUsePipelining") as! NSNumber
+ self._httpShouldUsePipelining = encodedUsePipelining.boolValue
}
open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ guard aCoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ aCoder.encode(self.url?._bridgeToObjectiveC(), forKey: "NS.url")
+ aCoder.encode(self._allHTTPHeaderFields?._bridgeToObjectiveC(), forKey: "NS._allHTTPHeaderFields")
+ aCoder.encode(self.mainDocumentURL?._bridgeToObjectiveC(), forKey: "NS.mainDocumentURL")
+ aCoder.encode(self.httpMethod?._bridgeToObjectiveC(), forKey: "NS.httpMethod")
+ aCoder.encode(self._cachePolicy.rawValue._bridgeToObjectiveC(), forKey: "NS._cachePolicy")
+ aCoder.encode(self._timeoutInterval._bridgeToObjectiveC(), forKey: "NS._timeoutInterval")
+ if let httpBody = self.httpBody?._bridgeToObjectiveC() {
+ let bytePtr = httpBody.bytes.bindMemory(to: UInt8.self, capacity: httpBody.length)
+ aCoder.encodeBytes(bytePtr, length: httpBody.length, forKey: "NS.httpBody")
+ }
+ //On macOS input stream is not encoded.
+ aCoder.encode(self._networkServiceType.rawValue._bridgeToObjectiveC(), forKey: "NS._networkServiceType")
+ aCoder.encode(self._allowsCellularAccess._bridgeToObjectiveC(), forKey: "NS._allowsCellularAccess")
+ aCoder.encode(self._httpShouldHandleCookies._bridgeToObjectiveC(), forKey: "NS._httpShouldHandleCookies")
+ aCoder.encode(self._httpShouldUsePipelining._bridgeToObjectiveC(), forKey: "NS._httpShouldUsePipelining")
+ }
+
+ open override func isEqual(_ object: Any?) -> Bool {
+ //On macOS this fields do not determine the result:
+ //allHTTPHeaderFields
+ //timeoutInterval
+ //httBody
+ //networkServiceType
+ //httpShouldUsePipelining
+ if let other = object as? NSURLRequest {
+ return other === self
+ || (other.url == self.url
+ && other.mainDocumentURL == self.mainDocumentURL
+ && other.httpMethod == self.httpMethod
+ && other._cachePolicy == self._cachePolicy
+ && other.httpBodyStream == self.httpBodyStream
+ && other._allowsCellularAccess == self._allowsCellularAccess
+ && other._httpShouldHandleCookies == self._httpShouldHandleCookies)
+ }
+ return false
}
/// Indicates that NSURLRequest implements the NSSecureCoding protocol.
@@ -289,7 +379,7 @@
/// example.
open class NSMutableURLRequest : NSURLRequest {
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ super.init(coder: aDecoder)
}
public convenience init(url: URL) {
diff --git a/Foundation/NSURLResponse.swift b/Foundation/NSURLResponse.swift
index e74f9f1..e39bfcf 100644
--- a/Foundation/NSURLResponse.swift
+++ b/Foundation/NSURLResponse.swift
@@ -23,11 +23,39 @@
}
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ guard aDecoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ if let encodedUrl = aDecoder.decodeObject(forKey: "NS.url") as? NSURL {
+ self.url = encodedUrl._swiftObject
+ }
+
+ if let encodedMimeType = aDecoder.decodeObject(forKey: "NS.mimeType") as? NSString {
+ self.mimeType = encodedMimeType._swiftObject
+ }
+
+ self.expectedContentLength = aDecoder.decodeInt64(forKey: "NS.expectedContentLength")
+
+ if let encodedEncodingName = aDecoder.decodeObject(forKey: "NS.textEncodingName") as? NSString {
+ self.textEncodingName = encodedEncodingName._swiftObject
+ }
+
+ if let encodedFilename = aDecoder.decodeObject(forKey: "NS.suggestedFilename") as? NSString {
+ self.suggestedFilename = encodedFilename._swiftObject
+ }
}
open func encode(with aCoder: NSCoder) {
- NSUnimplemented()
+ guard aCoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ aCoder.encode(self.url?._bridgeToObjectiveC(), forKey: "NS.url")
+ aCoder.encode(self.mimeType?._bridgeToObjectiveC(), forKey: "NS.mimeType")
+ aCoder.encode(self.expectedContentLength, forKey: "NS.expectedContentLength")
+ aCoder.encode(self.textEncodingName?._bridgeToObjectiveC(), forKey: "NS.textEncodingName")
+ aCoder.encode(self.suggestedFilename?._bridgeToObjectiveC(), forKey: "NS.suggestedFilename")
}
open override func copy() -> Any {
@@ -135,7 +163,27 @@
}
public required init?(coder aDecoder: NSCoder) {
- NSUnimplemented()
+ guard aDecoder.allowsKeyedCoding else {
+ preconditionFailure("Unkeyed coding is unsupported.")
+ }
+
+ self.statusCode = aDecoder.decodeInteger(forKey: "NS.statusCode")
+
+ if let encodedHeaders = aDecoder.decodeObject(forKey: "NS.allHeaderFields") as? NSDictionary {
+ self.allHeaderFields = encodedHeaders._swiftObject
+ } else {
+ self.allHeaderFields = [:]
+ }
+
+ super.init(coder: aDecoder)
+ }
+
+ open override func encode(with aCoder: NSCoder) {
+ super.encode(with: aCoder) //Will fail if .allowsKeyedCoding == false
+
+ aCoder.encode(self.statusCode, forKey: "NS.statusCode")
+ aCoder.encode(self.allHeaderFields._bridgeToObjectiveC(), forKey: "NS.allHeaderFields")
+
}
/// The HTTP status code of the receiver.
diff --git a/Foundation/NSXMLParser.swift b/Foundation/NSXMLParser.swift
index 1c8f3b9..b0c5c1f 100644
--- a/Foundation/NSXMLParser.swift
+++ b/Foundation/NSXMLParser.swift
@@ -42,7 +42,8 @@
}
}
-private func UTF8STRING(_ bytes: UnsafePointer<UInt8>) -> String? {
+private func UTF8STRING(_ bytes: UnsafePointer<UInt8>?) -> String? {
+ guard let bytes = bytes else { return nil }
// strlen operates on the wrong type, char*. We can't rebind the memory to a different type without knowing it's length,
// but since we know strlen is in libc, its safe to directly bitcast the pointer without worrying about multiple accesses
// of different types visible to the compiler.
@@ -243,16 +244,10 @@
return "\(prefixString!):\(suffixString!)"
}
-internal func _NSXMLParserStartElementNs(_ ctx: _CFXMLInterface, localname: UnsafePointer<UInt8>, prefix: UnsafePointer<UInt8>?, URI: UnsafePointer<UInt8>, nb_namespaces: Int32, namespaces: UnsafeMutablePointer<UnsafePointer<UInt8>?>, nb_attributes: Int32, nb_defaulted: Int32, attributes: UnsafeMutablePointer<UnsafePointer<UInt8>?>) -> Void {
+internal func _NSXMLParserStartElementNs(_ ctx: _CFXMLInterface, localname: UnsafePointer<UInt8>, prefix: UnsafePointer<UInt8>?, URI: UnsafePointer<UInt8>?, nb_namespaces: Int32, namespaces: UnsafeMutablePointer<UnsafePointer<UInt8>?>, nb_attributes: Int32, nb_defaulted: Int32, attributes: UnsafeMutablePointer<UnsafePointer<UInt8>?>) -> Void {
let parser = ctx.parser
- let reportQNameURI = parser.shouldProcessNamespaces
let reportNamespaces = parser.shouldReportNamespacePrefixes
- // Since strlen is in libc, it's safe to bitcast the UInt8 pointer argument to an Int8 (char *) pointer.
- let prefixLen = prefix != nil ? UInt(strlen(unsafeBitCast(prefix!, to: UnsafePointer<Int8>.self))) : 0
- let localnameString = (prefixLen == 0 || reportQNameURI) ? UTF8STRING(localname) : nil
- let qualifiedNameString = prefixLen != 0 ? _colonSeparatedStringFromPrefixAndSuffix(prefix!, UInt(prefixLen), localname, UInt(strlen(unsafeBitCast(localname, to: UnsafePointer<Int8>.self)))) : localnameString
- let namespaceURIString = reportQNameURI ? UTF8STRING(URI) : nil
-
+
var nsDict = [String:String]()
var attrDict = [String:String]()
if nb_attributes + nb_namespaces > 0 {
@@ -274,7 +269,7 @@
nsDict[k] = v
}
}
- if !reportQNameURI {
+ if !parser.shouldProcessNamespaces {
if let k = asAttrNamespaceNameString,
let v = namespaceValueString {
attrDict[k] = v
@@ -323,37 +318,47 @@
}
}
-
- if let delegate = parser.delegate {
- if reportQNameURI {
- delegate.parser(parser, didStartElement: localnameString!, namespaceURI: (namespaceURIString != nil ? namespaceURIString : ""), qualifiedName: (qualifiedNameString != nil ? qualifiedNameString : ""), attributes: attrDict)
- } else {
- delegate.parser(parser, didStartElement: qualifiedNameString!, namespaceURI: nil, qualifiedName: nil, attributes: attrDict)
+
+ var elementName: String = UTF8STRING(localname)!
+ var namespaceURI: String? = nil
+ var qualifiedName: String? = nil
+ if parser.shouldProcessNamespaces {
+ namespaceURI = UTF8STRING(URI) ?? ""
+ qualifiedName = elementName
+ if let prefix = UTF8STRING(prefix) {
+ qualifiedName = elementName + ":" + prefix
}
}
+ else if let prefix = UTF8STRING(prefix) {
+ elementName = elementName + ":" + prefix
+ }
+
+ parser.delegate?.parser(parser, didStartElement: elementName, namespaceURI: namespaceURI, qualifiedName: qualifiedName, attributes: attrDict)
}
-internal func _NSXMLParserEndElementNs(_ ctx: _CFXMLInterface , localname: UnsafePointer<UInt8>, prefix: UnsafePointer<UInt8>?, URI: UnsafePointer<UInt8>) -> Void {
+internal func _NSXMLParserEndElementNs(_ ctx: _CFXMLInterface , localname: UnsafePointer<UInt8>, prefix: UnsafePointer<UInt8>?, URI: UnsafePointer<UInt8>?) -> Void {
let parser = ctx.parser
- let reportQNameURI = parser.shouldProcessNamespaces
- let prefixLen = prefix != nil ? strlen(unsafeBitCast(prefix!, to: UnsafePointer<Int8>.self)) : 0
- let localnameString = (prefixLen == 0 || reportQNameURI) ? UTF8STRING(localname) : nil
- let nilStr: String? = nil
- let qualifiedNameString = (prefixLen != 0) ? _colonSeparatedStringFromPrefixAndSuffix(prefix!, UInt(prefixLen), localname, UInt(strlen(unsafeBitCast(localname, to: UnsafePointer<Int8>.self)))) : nilStr
- let namespaceURIString = reportQNameURI ? UTF8STRING(URI) : nilStr
-
-
- if let delegate = parser.delegate {
- if reportQNameURI {
- // When reporting namespace info, the delegate parameters are not passed in nil
- delegate.parser(parser, didEndElement: localnameString!, namespaceURI: namespaceURIString == nil ? "" : namespaceURIString, qualifiedName: qualifiedNameString == nil ? "" : qualifiedNameString)
- } else {
- delegate.parser(parser, didEndElement: qualifiedNameString!, namespaceURI: nil, qualifiedName: nil)
+
+ var elementName: String = UTF8STRING(localname)!
+ var namespaceURI: String? = nil
+ var qualifiedName: String? = nil
+ if parser.shouldProcessNamespaces {
+ namespaceURI = UTF8STRING(URI) ?? ""
+ qualifiedName = elementName
+ if let prefix = UTF8STRING(prefix) {
+ qualifiedName = elementName + ":" + prefix
}
}
-
+ else if let prefix = UTF8STRING(prefix) {
+ elementName = elementName + ":" + prefix
+ }
+
+ parser.delegate?.parser(parser, didEndElement: elementName, namespaceURI: namespaceURI, qualifiedName: qualifiedName)
+
// Pop the last namespaces that were pushed (safe since XML is balanced)
- parser._popNamespaces()
+ if parser.shouldReportNamespacePrefixes {
+ parser._popNamespaces()
+ }
}
internal func _NSXMLParserCharacters(_ ctx: _CFXMLInterface, ch: UnsafePointer<UInt8>, len: Int32) -> Void {
@@ -410,8 +415,10 @@
private var _handler: _CFXMLInterfaceSAXHandler
internal var _stream: InputStream?
internal var _data: Data?
+
internal var _chunkSize = Int(4096 * 32) // a suitably large number for a decent chunk size
- internal var _haveDetectedEncoding = false
+ // This chunk of data stores the head of the stream. We know we have enough information for encoding
+ // when there are atleast 4 bytes in here.
internal var _bomChunk: Data?
fileprivate var _parserContext: _CFXMLInterfaceParserContext?
internal var _delegateAborted = false
@@ -500,72 +507,52 @@
internal func parseData(_ data: Data) -> Bool {
_CFXMLInterfaceSetStructuredErrorFunc(interface, _structuredErrorFunc)
- var result = true
- /* The vast majority of this method just deals with ensuring we do a single parse
- on the first 4 received bytes before continuing on to the actual incremental section */
- if _haveDetectedEncoding {
- var totalLength = data.count
- if let chunk = _bomChunk {
- totalLength += chunk.count
+
+ let handler: _CFXMLInterfaceSAXHandler? = (delegate != nil ? _handler : nil)
+ let unparsedData: Data
+ // If the parser context is nil, we have not received enough bytes to create the push parser
+ if _parserContext == nil {
+ // Look at the bomChunk and this data
+ let bomChunk: Data = {
+ guard var bomChunk = _bomChunk else {
+ return data
+ }
+ bomChunk.append(data)
+ return bomChunk
+ }()
+ // If we have not received 4 bytes, save the bomChunk for next pass
+ if bomChunk.count < 4 {
+ _bomChunk = bomChunk
+ return false
}
- if (totalLength < 4) {
- if let chunk = _bomChunk {
- var newData = Data()
- newData.append(chunk)
- newData.append(data)
- _bomChunk = newData
- } else {
- _bomChunk = data
- }
- } else {
- var allExistingData: Data
- if let chunk = _bomChunk {
- var newData = Data()
- newData.append(chunk)
- newData.append(data)
- allExistingData = newData
- } else {
- allExistingData = data
- }
-
- var handler: _CFXMLInterfaceSAXHandler? = nil
- if delegate != nil {
- handler = _handler
- }
-
- _parserContext = allExistingData.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> _CFXMLInterfaceParserContext in
- return _CFXMLInterfaceCreatePushParserCtxt(handler, interface, bytes, 4, nil)
- }
-
- var options = _kCFXMLInterfaceRecover | _kCFXMLInterfaceNoEnt // substitute entities, recover on errors
- if shouldResolveExternalEntities {
- options |= _kCFXMLInterfaceDTDLoad
- }
-
- if handler == nil {
- options |= (_kCFXMLInterfaceNoError | _kCFXMLInterfaceNoWarning)
- }
-
- _CFXMLInterfaceCtxtUseOptions(_parserContext, options)
- _haveDetectedEncoding = true
- _bomChunk = nil
-
- if (totalLength > 4) {
- let remainingData = allExistingData.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Data in
- let ptr = bytes.advanced(by: 4)
- return Data(bytesNoCopy: ptr, count: totalLength - 4, deallocator: .none)
- }
-
- let _ = parseData(remainingData)
- }
+ // Prepare options (substitute entities, recover on errors)
+ var options = _kCFXMLInterfaceRecover | _kCFXMLInterfaceNoEnt
+ if shouldResolveExternalEntities {
+ options |= _kCFXMLInterfaceDTDLoad
}
- } else {
- let parseResult = data.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Int32 in
- return _CFXMLInterfaceParseChunk(_parserContext, bytes, Int32(data.count), 0)
+ if handler == nil {
+ options |= (_kCFXMLInterfaceNoError | _kCFXMLInterfaceNoWarning)
}
-
- result = _handleParseResult(parseResult)
+
+ // Create the push context with the first 4 bytes
+ bomChunk.withUnsafeBytes { bytes in
+ _parserContext = _CFXMLInterfaceCreatePushParserCtxt(handler, interface, bytes, 4, nil)
+ }
+ _CFXMLInterfaceCtxtUseOptions(_parserContext, options)
+ // Prepare the remaining data for parsing
+ let dataRange = bomChunk.indices
+ let unparsed = Range(uncheckedBounds: (dataRange.startIndex.advanced(by: 4), dataRange.endIndex))
+ unparsedData = bomChunk.subdata(in: unparsed)
}
+ else {
+ unparsedData = data
+ }
+
+ let parseResult = unparsedData.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Int32 in
+ return _CFXMLInterfaceParseChunk(_parserContext, bytes, Int32(unparsedData.count), 0)
+ }
+
+ let result = _handleParseResult(parseResult)
_CFXMLInterfaceSetStructuredErrorFunc(interface, nil)
return result
}
@@ -745,13 +732,13 @@
func parser(_ parser: XMLParser, resolveExternalEntityName name: String, systemID: String?) -> Data?
// this gives the delegate an opportunity to resolve an external entity itself and reply with the resulting data.
- func parser(_ parser: XMLParser, parseErrorOccurred parseError: NSError)
+ func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error)
// ...and this reports a fatal error to the delegate. The parser will stop parsing.
- func parser(_ parser: XMLParser, validationErrorOccurred validationError: NSError)
+ func parser(_ parser: XMLParser, validationErrorOccurred validationError: Error)
}
-extension XMLParserDelegate {
+public extension XMLParserDelegate {
func parserDidStartDocument(_ parser: XMLParser) { }
func parserDidEndDocument(_ parser: XMLParser) { }
@@ -788,9 +775,9 @@
func parser(_ parser: XMLParser, resolveExternalEntityName name: String, systemID: String?) -> Data? { return nil }
- func parser(_ parser: XMLParser, parseErrorOccurred parseError: NSError) { }
+ func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) { }
- func parser(_ parser: XMLParser, validationErrorOccurred validationError: NSError) { }
+ func parser(_ parser: XMLParser, validationErrorOccurred validationError: Error) { }
}
extension XMLParser {
diff --git a/TestFoundation/TestNSArray.swift b/TestFoundation/TestNSArray.swift
index 132747b..c905e52 100644
--- a/TestFoundation/TestNSArray.swift
+++ b/TestFoundation/TestNSArray.swift
@@ -500,7 +500,7 @@
}
private func createTestFile(_ path: String, _contents: Data) -> String? {
- let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().uuidString + "/"
+ let tempDir = NSTemporaryDirectory() + "TestFoundation_Playground_" + NSUUID().uuidString + "/"
do {
try FileManager.default.createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
if FileManager.default.createFile(atPath: tempDir + "/" + path, contents: _contents, attributes: nil) {
diff --git a/TestFoundation/TestNSBundle.swift b/TestFoundation/TestNSBundle.swift
index e427992..8e40179 100644
--- a/TestFoundation/TestNSBundle.swift
+++ b/TestFoundation/TestNSBundle.swift
@@ -108,7 +108,7 @@
private func _setupPlayground() -> String? {
// Make sure the directory is uniquely named
- let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().uuidString + "/"
+ let tempDir = NSTemporaryDirectory() + "TestFoundation_Playground_" + NSUUID().uuidString + "/"
do {
try FileManager.default.createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
@@ -179,7 +179,7 @@
}
func test_bundleWithInvalidPath(){
- let bundleInvalid = Bundle(path: "/tmp/test.playground")
+ let bundleInvalid = Bundle(path: NSTemporaryDirectory() + "test.playground")
XCTAssertNil(bundleInvalid)
}
diff --git a/TestFoundation/TestNSDictionary.swift b/TestFoundation/TestNSDictionary.swift
index 002a119..ff415ef 100644
--- a/TestFoundation/TestNSDictionary.swift
+++ b/TestFoundation/TestNSDictionary.swift
@@ -205,7 +205,7 @@
}
private func createTestFile(_ path: String, _contents: Data) -> String? {
- let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().uuidString + "/"
+ let tempDir = NSTemporaryDirectory() + "TestFoundation_Playground_" + NSUUID().uuidString + "/"
do {
try FileManager.default.createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
if FileManager.default.createFile(atPath: tempDir + "/" + path, contents: _contents,
diff --git a/TestFoundation/TestNSFileHandle.swift b/TestFoundation/TestNSFileHandle.swift
old mode 100755
new mode 100644
diff --git a/TestFoundation/TestNSFileManager.swift b/TestFoundation/TestNSFileManager.swift
index b0c9afd..1bdffd3 100644
--- a/TestFoundation/TestNSFileManager.swift
+++ b/TestFoundation/TestNSFileManager.swift
@@ -38,7 +38,7 @@
func test_createDirectory() {
let fm = FileManager.default
- let path = "/tmp/testdir\(NSUUID().uuidString)"
+ let path = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)"
ignoreError { try fm.removeItem(atPath: path) }
@@ -63,7 +63,7 @@
func test_createFile() {
let fm = FileManager.default
- let path = "/tmp/testfile\(NSUUID().uuidString)"
+ let path = NSTemporaryDirectory() + "testfile\(NSUUID().uuidString)"
ignoreError { try fm.removeItem(atPath: path) }
@@ -83,8 +83,8 @@
func test_moveFile() {
let fm = FileManager.default
- let path = "/tmp/testfile\(NSUUID().uuidString)"
- let path2 = "/tmp/testfile2\(NSUUID().uuidString)"
+ let path = NSTemporaryDirectory() + "testfile\(NSUUID().uuidString)"
+ let path2 = NSTemporaryDirectory() + "testfile2\(NSUUID().uuidString)"
func cleanup() {
ignoreError { try fm.removeItem(atPath: path) }
@@ -114,7 +114,7 @@
func test_fileAttributes() {
let fm = FileManager.default
- let path = "/tmp/test_fileAttributes\(NSUUID().uuidString)"
+ let path = NSTemporaryDirectory() + "test_fileAttributes\(NSUUID().uuidString)"
ignoreError { try fm.removeItem(atPath: path) }
@@ -161,7 +161,7 @@
}
func test_setFileAttributes() {
- let path = "/tmp/test_setFileAttributes\(NSUUID().uuidString)"
+ let path = NSTemporaryDirectory() + "test_setFileAttributes\(NSUUID().uuidString)"
let fm = FileManager.default
ignoreError { try fm.removeItem(atPath: path) }
@@ -189,10 +189,10 @@
func test_pathEnumerator() {
let fm = FileManager.default
let testDirName = "testdir\(NSUUID().uuidString)"
- let basePath = "/tmp/\(testDirName)"
- let itemPath = "/tmp/\(testDirName)/item"
- let basePath2 = "/tmp/\(testDirName)/path2"
- let itemPath2 = "/tmp/\(testDirName)/path2/item"
+ let basePath = NSTemporaryDirectory() + "\(testDirName)"
+ let itemPath = NSTemporaryDirectory() + "\(testDirName)/item"
+ let basePath2 = NSTemporaryDirectory() + "\(testDirName)/path2"
+ let itemPath2 = NSTemporaryDirectory() + "\(testDirName)/path2/item"
ignoreError { try fm.removeItem(atPath: basePath) }
@@ -222,8 +222,8 @@
func test_directoryEnumerator() {
let fm = FileManager.default
let testDirName = "testdir\(NSUUID().uuidString)"
- let path = "/tmp/\(testDirName)"
- let itemPath = "/tmp/\(testDirName)/item"
+ let path = NSTemporaryDirectory() + "\(testDirName)"
+ let itemPath = NSTemporaryDirectory() + "\(testDirName)/item"
ignoreError { try fm.removeItem(atPath: path) }
@@ -244,8 +244,8 @@
XCTFail()
}
- let subDirPath = "/tmp/\(testDirName)/testdir2"
- let subDirItemPath = "/tmp/\(testDirName)/testdir2/item"
+ let subDirPath = NSTemporaryDirectory() + "\(testDirName)/testdir2"
+ let subDirItemPath = NSTemporaryDirectory() + "\(testDirName)/testdir2/item"
do {
try fm.createDirectory(atPath: subDirPath, withIntermediateDirectories: false, attributes: nil)
let _ = fm.createFile(atPath: subDirItemPath, contents: Data(), attributes: nil)
@@ -320,9 +320,9 @@
func test_contentsOfDirectoryAtPath() {
let fm = FileManager.default
let testDirName = "testdir\(NSUUID().uuidString)"
- let path = "/tmp/\(testDirName)"
- let itemPath1 = "/tmp/\(testDirName)/item"
- let itemPath2 = "/tmp/\(testDirName)/item2"
+ let path = NSTemporaryDirectory() + "\(testDirName)"
+ let itemPath1 = NSTemporaryDirectory() + "\(testDirName)/item"
+ let itemPath2 = NSTemporaryDirectory() + "\(testDirName)/item2"
ignoreError { try fm.removeItem(atPath: path) }
@@ -363,11 +363,11 @@
func test_subpathsOfDirectoryAtPath() {
let fm = FileManager.default
- let path = "/tmp/testdir"
- let path2 = "/tmp/testdir/sub"
- let itemPath1 = "/tmp/testdir/item"
- let itemPath2 = "/tmp/testdir/item2"
- let itemPath3 = "/tmp/testdir/sub/item3"
+ let path = NSTemporaryDirectory() + "testdir"
+ let path2 = NSTemporaryDirectory() + "testdir/sub"
+ let itemPath1 = NSTemporaryDirectory() + "testdir/item"
+ let itemPath2 = NSTemporaryDirectory() + "testdir/item2"
+ let itemPath3 = NSTemporaryDirectory() + "testdir/sub/item3"
ignoreError { try fm.removeItem(atPath: path) }
diff --git a/TestFoundation/TestNSJSONSerialization.swift b/TestFoundation/TestNSJSONSerialization.swift
index d40a1c0..3ce12e8 100644
--- a/TestFoundation/TestNSJSONSerialization.swift
+++ b/TestFoundation/TestNSJSONSerialization.swift
@@ -777,7 +777,7 @@
// Cannot generate "true"/"false" currently
json = [NSNumber(value:false),NSNumber(value:true)]
- XCTAssertEqual(try trySerialize(json), "[0,1]")
+ XCTAssertEqual(try trySerialize(json), "[false,true]")
}
func test_serialize_stringEscaping() {
@@ -931,16 +931,18 @@
func test_booleanJSONObject() {
do {
- let mydata = try JSONSerialization.data(withJSONObject: [true])
- XCTAssertEqual(String(data: mydata, encoding: String.Encoding.utf8), "[1]")
+ let objectLikeBoolArray = try JSONSerialization.data(withJSONObject: [true, NSNumber(value: false), NSNumber(value: true)] as Array<Any>)
+ XCTAssertEqual(String(data: objectLikeBoolArray, encoding: .utf8), "[true,false,true]")
+ let valueLikeBoolArray = try JSONSerialization.data(withJSONObject: [false, true, false])
+ XCTAssertEqual(String(data: valueLikeBoolArray, encoding: .utf8), "[false,true,false]")
} catch {
XCTFail("Failed during serialization")
}
- XCTAssertTrue(JSONSerialization.isValidJSONObject([1]))
+ XCTAssertTrue(JSONSerialization.isValidJSONObject([true]))
}
private func createTestFile(_ path: String,_contents: Data) -> String? {
- let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().uuidString + "/"
+ let tempDir = NSTemporaryDirectory() + "TestFoundation_Playground_" + NSUUID().uuidString + "/"
do {
try FileManager.default.createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
if FileManager.default.createFile(atPath: tempDir + "/" + path, contents: _contents,
diff --git a/TestFoundation/TestNSLocale.swift b/TestFoundation/TestNSLocale.swift
index 3d18791..f83edf3 100644
--- a/TestFoundation/TestNSLocale.swift
+++ b/TestFoundation/TestNSLocale.swift
@@ -19,9 +19,24 @@
static var allTests: [(String, (TestNSLocale) -> () throws -> Void)] {
return [
("test_constants", test_constants),
+ ("test_Identifier", test_Identifier),
("test_copy", test_copy)
]
}
+
+ func test_Identifier() {
+ // Current locale identifier should not be empty
+ // Or things like NSNumberFormatter spellOut style won't work
+ XCTAssertFalse(Locale.current.identifier.isEmpty)
+
+ let enUSID = "en_US"
+ let locale = Locale(identifier: enUSID)
+ XCTAssertEqual(enUSID, locale.identifier)
+
+ let deDEID = "de_DE"
+ let germanLocale = Locale(identifier: deDEID)
+ XCTAssertEqual(deDEID, germanLocale.identifier)
+ }
func test_constants() {
XCTAssertEqual(NSCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification",
diff --git a/TestFoundation/TestNSNotificationCenter.swift b/TestFoundation/TestNSNotificationCenter.swift
old mode 100755
new mode 100644
diff --git a/TestFoundation/TestNSNumberFormatter.swift b/TestFoundation/TestNSNumberFormatter.swift
index 9511770..222b3d2 100644
--- a/TestFoundation/TestNSNumberFormatter.swift
+++ b/TestFoundation/TestNSNumberFormatter.swift
@@ -53,7 +53,9 @@
("test_lenient", test_lenient),
("test_minimumSignificantDigits", test_minimumSignificantDigits),
("test_maximumSignificantDigits", test_maximumSignificantDigits),
- ("test_stringFor", test_stringFor)
+ ("test_stringFor", test_stringFor),
+ ("test_numberFrom", test_numberFrom),
+ //("test_en_US_initialValues", test_en_US_initialValues)
]
}
@@ -68,11 +70,15 @@
XCTAssertEqual(formattedString, "T 42_00")
*/
}
-
+
func test_decimalSeparator() {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
- numberFormatter.decimalSeparator = "-"
+
+ let separator = "-"
+ numberFormatter.decimalSeparator = separator
+ XCTAssertEqual(numberFormatter.decimalSeparator, separator)
+
let formattedString = numberFormatter.string(from: 42.42)
XCTAssertEqual(formattedString, "42-42")
}
@@ -147,14 +153,28 @@
}
func test_plusSignSymbol() {
- //FIXME: How do we show the plus sign from a NSNumberFormatter?
+ // ex. 1.0E+1 in scientific notation
+ let numberFormatter = NumberFormatter()
+ let format = "#E+0"
+ numberFormatter.format = format
+ XCTAssertEqual(numberFormatter.format, format)
-// let numberFormatter = NumberFormatter()
-// numberFormatter.plusSign = "π"
-// let formattedString = numberFormatter.stringFromNumber(42)
-// XCTAssertEqual(formattedString, "π42")
+ let sign = "π"
+ numberFormatter.plusSign = sign
+ XCTAssertEqual(numberFormatter.plusSign, sign)
+
+ let formattedString = numberFormatter.string(from: 420000000000000000)
+ XCTAssertNotNil(formattedString)
+ XCTAssertEqual(formattedString, "4.2Eπ17")
+
+ // Verify a negative exponent does not have the π
+ let noPlusString = numberFormatter.string(from: -0.420)
+ XCTAssertNotNil(noPlusString)
+ if let fmt = noPlusString {
+ XCTAssertFalse(fmt.contains(sign), "Expected format of -0.420 (-4.2E-1) shouldn't have a plus sign which was set as \(sign)")
+ }
}
-
+
func test_currencySymbol() {
// Disabled due to [SR-250]
/*
@@ -316,14 +336,30 @@
*/
}
- //FIXME: Something is wrong with numberFromString implementation, I don't know exactly why, but it's not working.
func test_lenient() {
-// let numberFormatter = NumberFormatter()
-// numberFormatter.numberStyle = .CurrencyStyle
-// let nilNumberBeforeLenient = numberFormatter.numberFromString("42")
+ let numberFormatter = NumberFormatter()
+ // Not lenient by default
+ XCTAssertFalse(numberFormatter.isLenient)
+
+ // Lenient allows wrong style -- not lenient here
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.numberStyle, .spellOut)
+// let nilNumber = numberFormatter.number(from: "2.22")
+ // FIXME: Not nil on Linux?
+ //XCTAssertNil(nilNumber)
+ // Lenient allows wrong style
+ numberFormatter.isLenient = true
+ XCTAssertTrue(numberFormatter.isLenient)
+ let number = numberFormatter.number(from: "2.22")
+ XCTAssertEqual(number, 2.22)
+
+ // TODO: Add some tests with currency after [SR-250] resolved
+// numberFormatter.numberStyle = .currency
+// let nilNumberBeforeLenient = numberFormatter.number(from: "42")
+//
// XCTAssertNil(nilNumberBeforeLenient)
-// numberFormatter.lenient = true
-// let numberAfterLenient = numberFormatter.numberFromString("42.42")
+// numberFormatter.isLenient = true
+// let numberAfterLenient = numberFormatter.number(from: "42.42")
// XCTAssertEqual(numberAfterLenient, 42.42)
}
@@ -353,7 +389,76 @@
XCTAssertEqual(numberFormatter.string(for: NSNumber(value: 99.1))!, "99")
XCTAssertNil(numberFormatter.string(for: "NaN"))
XCTAssertNil(numberFormatter.string(for: NSString(string: "NaN")))
+
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.string(for: 234), "two hundred thirty-four")
+ XCTAssertEqual(numberFormatter.string(for: 2007), "two thousand seven")
+ XCTAssertEqual(numberFormatter.string(for: 3), "three")
+ XCTAssertEqual(numberFormatter.string(for: 0.3), "zero point three")
+
+ numberFormatter.locale = Locale(identifier: "zh_CN")
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.string(from: 11.4), "εδΈηΉε")
+
+ numberFormatter.locale = Locale(identifier: "fr_FR")
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.string(from: 11.4), "onze virgule quatre")
+
}
-
+
+ func test_numberFrom() {
+ let numberFormatter = NumberFormatter()
+ XCTAssertEqual(numberFormatter.number(from: "10"), 10)
+ XCTAssertEqual(numberFormatter.number(from: "3.14"), 3.14)
+ XCTAssertEqual(numberFormatter.number(from: "0.01"), 0.01)
+ XCTAssertEqual(numberFormatter.number(from: ".01"), 0.01)
+
+ // These don't work unless lenient/style set
+ numberFormatter.numberStyle = .decimal
+ XCTAssertEqual(numberFormatter.number(from: "1,001"), 1001)
+ XCTAssertEqual(numberFormatter.number(from: "1,050,001"), 1050001)
+
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.number(from: "two thousand and seven"), 2007)
+ XCTAssertEqual(numberFormatter.number(from: "one point zero"), 1.0)
+ XCTAssertEqual(numberFormatter.number(from: "one hundred million"), 1E8)
+
+ numberFormatter.locale = Locale(identifier: "zh_CN")
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.number(from: "εδΈηΉε"), 11.4)
+
+ numberFormatter.locale = Locale(identifier: "fr_FR")
+ numberFormatter.numberStyle = .spellOut
+ XCTAssertEqual(numberFormatter.number(from: "onze virgule quatre"), 11.4)
+ }
+
+ func test_en_US_initialValues() {
+ // Symbols should be extractable
+ // At one point, none of this passed!
+
+ let numberFormatter = NumberFormatter();
+ numberFormatter.locale = Locale(identifier: "en_US")
+
+ // TODO: Check if this is true for all versions...
+ XCTAssertEqual(numberFormatter.format, "#;0;#")
+
+ XCTAssertEqual(numberFormatter.plusSign, "+")
+ XCTAssertEqual(numberFormatter.minusSign, "-")
+ XCTAssertEqual(numberFormatter.decimalSeparator, ".")
+ XCTAssertEqual(numberFormatter.groupingSeparator, ",")
+ XCTAssertEqual(numberFormatter.nilSymbol, "")
+ XCTAssertEqual(numberFormatter.notANumberSymbol, "NaN")
+ XCTAssertEqual(numberFormatter.positiveInfinitySymbol, "+∞")
+ XCTAssertEqual(numberFormatter.negativeInfinitySymbol, "-∞")
+ XCTAssertEqual(numberFormatter.positivePrefix, "")
+ XCTAssertEqual(numberFormatter.negativePrefix, "-")
+ XCTAssertEqual(numberFormatter.positiveSuffix, "")
+ XCTAssertEqual(numberFormatter.negativeSuffix, "")
+ XCTAssertEqual(numberFormatter.percentSymbol, "%")
+ XCTAssertEqual(numberFormatter.perMillSymbol, "‰")
+ XCTAssertEqual(numberFormatter.exponentSymbol, "E")
+ XCTAssertEqual(numberFormatter.groupingSeparator, ",")
+ XCTAssertEqual(numberFormatter.paddingCharacter, "*")
+ }
}
diff --git a/TestFoundation/TestNSPredicate.swift b/TestFoundation/TestNSPredicate.swift
index 4275d9a..641d605 100644
--- a/TestFoundation/TestNSPredicate.swift
+++ b/TestFoundation/TestNSPredicate.swift
@@ -27,6 +27,8 @@
("test_filterNSMutableSet", test_filterNSMutableSet),
("test_filterNSOrderedSet", test_filterNSOrderedSet),
("test_filterNSMutableOrderedSet", test_filterNSMutableOrderedSet),
+ ("test_NSCoding", test_NSCoding),
+ ("test_copy", test_copy),
]
}
@@ -94,4 +96,15 @@
expectedOrderedSet.addObjects(from: expectedArray)
XCTAssertEqual(expectedOrderedSet, orderedSet)
}
+
+ func test_NSCoding() {
+ let predicateA = NSPredicate(value: true)
+ let predicateB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: predicateA)) as! NSPredicate
+ XCTAssertEqual(predicateA, predicateB, "Archived then unarchived uuid must be equal.")
+ }
+
+ func test_copy() {
+ let predicate = NSPredicate(value: true)
+ XCTAssert(predicate.isEqual(predicate.copy()))
+ }
}
diff --git a/TestFoundation/TestNSRange.swift b/TestFoundation/TestNSRange.swift
index 927e989..75a6471 100644
--- a/TestFoundation/TestNSRange.swift
+++ b/TestFoundation/TestNSRange.swift
@@ -21,8 +21,7 @@
static var allTests: [(String, (TestNSRange) -> () throws -> Void)] {
return [
- // currently disabled due to pending requirements for NSString
- // ("test_NSRangeFromString", test_NSRangeFromString ),
+ ("test_NSRangeFromString", test_NSRangeFromString ),
("test_NSRangeBridging", test_NSRangeBridging),
("test_NSMaxRange", test_NSMaxRange),
("test_NSLocationInRange", test_NSLocationInRange),
diff --git a/TestFoundation/TestNSRunLoop.swift b/TestFoundation/TestNSRunLoop.swift
old mode 100755
new mode 100644
diff --git a/TestFoundation/TestNSStream.swift b/TestFoundation/TestNSStream.swift
index f2daf43..8bb4c5c 100644
--- a/TestFoundation/TestNSStream.swift
+++ b/TestFoundation/TestNSStream.swift
@@ -118,7 +118,7 @@
}
func test_InputStreamInvalidPath() {
- let fileStream: InputStream = InputStream(fileAtPath: "/tmp/file.txt")!
+ let fileStream: InputStream = InputStream(fileAtPath: NSTemporaryDirectory() + "file.txt")!
XCTAssertEqual(Stream.Status.notOpen, fileStream.streamStatus)
fileStream.open()
XCTAssertEqual(Stream.Status.error, fileStream.streamStatus)
@@ -217,7 +217,7 @@
}
private func createTestFile(_ path: String, _contents: Data) -> String? {
- let tempDir = "/tmp/TestFoundation_Playground_" + NSUUID().uuidString + "/"
+ let tempDir = NSTemporaryDirectory() + "TestFoundation_Playground_" + NSUUID().uuidString + "/"
do {
try FileManager.default.createDirectory(atPath: tempDir, withIntermediateDirectories: false, attributes: nil)
if FileManager.default.createFile(atPath: tempDir + "/" + path, contents: _contents,
diff --git a/TestFoundation/TestNSString.swift b/TestFoundation/TestNSString.swift
index ebb8fab..362e075 100644
--- a/TestFoundation/TestNSString.swift
+++ b/TestFoundation/TestNSString.swift
@@ -419,11 +419,11 @@
func test_completePathIntoString() {
let fileNames = [
- "/tmp/Test_completePathIntoString_01",
- "/tmp/test_completePathIntoString_02",
- "/tmp/test_completePathIntoString_01.txt",
- "/tmp/test_completePathIntoString_01.dat",
- "/tmp/test_completePathIntoString_03.DAT"
+ NSTemporaryDirectory() + "Test_completePathIntoString_01",
+ NSTemporaryDirectory() + "test_completePathIntoString_02",
+ NSTemporaryDirectory() + "test_completePathIntoString_01.txt",
+ NSTemporaryDirectory() + "test_completePathIntoString_01.dat",
+ NSTemporaryDirectory() + "test_completePathIntoString_03.DAT"
]
guard ensureFiles(fileNames) else {
@@ -432,7 +432,7 @@
}
let tmpPath = { (path: String) -> String in
- return "/tmp/\(path)"
+ return NSTemporaryDirectory() + "\(path)"
}
do {
@@ -463,9 +463,9 @@
}
let fileNames2 = [
- "/tmp/ABC/",
- "/tmp/ABCD/",
- "/tmp/abcde"
+ NSTemporaryDirectory() + "ABC/",
+ NSTemporaryDirectory() + "ABCD/",
+ NSTemporaryDirectory() + "abcde"
]
guard ensureFiles(fileNames2) else {
@@ -571,7 +571,7 @@
// Next check has no sense on Linux due to case sensitive file system.
#if os(OSX)
- guard ensureFiles(["/tmp/ABC/temp.txt"]) else {
+ guard ensureFiles([NSTemporaryDirectory() + "ABC/temp.txt"]) else {
XCTAssert(false, "Could not create temp files for testing.")
return
}
diff --git a/TestFoundation/TestNSTimer.swift b/TestFoundation/TestNSTimer.swift
old mode 100755
new mode 100644
diff --git a/TestFoundation/TestNSURL.swift b/TestFoundation/TestNSURL.swift
index 87409b5..55a57e6 100644
--- a/TestFoundation/TestNSURL.swift
+++ b/TestFoundation/TestNSURL.swift
@@ -352,7 +352,7 @@
func test_URLByResolvingSymlinksInPath() {
let files = [
- "/tmp/ABC/test_URLByResolvingSymlinksInPath"
+ NSTemporaryDirectory() + "ABC/test_URLByResolvingSymlinksInPath"
]
guard ensureFiles(files) else {
@@ -389,14 +389,14 @@
let result = url.resolvingSymlinksInPath().absoluteString
XCTAssertEqual(result, "file:///private/")
}
- #endif
-
+ #else
do {
let url = URL(fileURLWithPath: "/tmp/ABC/test_URLByResolvingSymlinksInPath")
let result = url.resolvingSymlinksInPath().absoluteString
XCTAssertEqual(result, "file:///tmp/ABC/test_URLByResolvingSymlinksInPath", "URLByResolvingSymlinksInPath appends trailing slash for existing directories only")
}
-
+ #endif
+
do {
let url = URL(fileURLWithPath: "/tmp/ABC/..")
let result = url.resolvingSymlinksInPath().absoluteString
diff --git a/TestFoundation/TestNSURLRequest.swift b/TestFoundation/TestNSURLRequest.swift
index 5dde4ef..b9b0353 100644
--- a/TestFoundation/TestNSURLRequest.swift
+++ b/TestFoundation/TestNSURLRequest.swift
@@ -27,6 +27,9 @@
("test_mutableCopy_1", test_mutableCopy_1),
("test_mutableCopy_2", test_mutableCopy_2),
("test_mutableCopy_3", test_mutableCopy_3),
+ ("test_NSCoding_1", test_NSCoding_1),
+ ("test_NSCoding_2", test_NSCoding_2),
+ ("test_NSCoding_3", test_NSCoding_3)
]
}
@@ -203,4 +206,38 @@
XCTAssertEqual(originalRequest.url, urlA)
XCTAssertNil(originalRequest.allHTTPHeaderFields)
}
+
+ func test_NSCoding_1() {
+ let url = URL(string: "https://apple.com")!
+ let requestA = NSURLRequest(url: url)
+ let requestB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: requestA)) as! NSURLRequest
+ XCTAssertEqual(requestA, requestB, "Archived then unarchived url request must be equal.")
+ }
+
+ func test_NSCoding_2() {
+ let url = URL(string: "https://apple.com")!
+ let requestA = NSMutableURLRequest(url: url)
+ //Also checks crash on NSData.bytes
+ requestA.httpBody = Data()
+ let requestB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: requestA)) as! NSURLRequest
+ XCTAssertEqual(requestA, requestB, "Archived then unarchived url request must be equal.")
+ //Check `.httpBody` as it is not checked in `isEqual(_:)`
+ XCTAssertEqual(requestB.httpBody, requestA.httpBody)
+ }
+
+ func test_NSCoding_3() {
+ let url = URL(string: "https://apple.com")!
+ let urlForDocument = URL(string: "http://ibm.com")!
+
+ let requestA = NSMutableURLRequest(url: url)
+ requestA.mainDocumentURL = urlForDocument
+ //Also checks crash on NSData.bytes
+ requestA.httpBody = Data(bytes: [1, 2, 3])
+ let requestB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: requestA)) as! NSURLRequest
+ XCTAssertEqual(requestA, requestB, "Archived then unarchived url request must be equal.")
+ //Check `.httpBody` as it is not checked in `isEqual(_:)`
+ XCTAssertNotNil(requestB.httpBody)
+ XCTAssertEqual(3, requestB.httpBody!.count)
+ XCTAssertEqual(requestB.httpBody, requestA.httpBody)
+ }
}
diff --git a/TestFoundation/TestNSURLResponse.swift b/TestFoundation/TestNSURLResponse.swift
index 9e67ffa..dfece22 100644
--- a/TestFoundation/TestNSURLResponse.swift
+++ b/TestFoundation/TestNSURLResponse.swift
@@ -29,6 +29,7 @@
("test_suggestedFilename_2", test_suggestedFilename_2),
("test_suggestedFilename_3", test_suggestedFilename_3),
("test_copywithzone", test_copyWithZone),
+ ("test_NSCoding", test_NSCoding),
]
}
@@ -91,6 +92,19 @@
let res = URLResponse(url: url, mimeType: "txt", expectedContentLength: 0, textEncodingName: nil)
XCTAssertTrue(res.isEqual(res.copy() as! NSObject))
}
+
+ func test_NSCoding() {
+ let url = URL(string: "https://apple.com")!
+ let responseA = URLResponse(url: url, mimeType: "txt", expectedContentLength: 0, textEncodingName: nil)
+ let responseB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: responseA)) as! URLResponse
+
+ //On macOS unarchived Archived then unarchived `URLResponse` is not equal.
+ XCTAssertEqual(responseA.url, responseB.url, "Archived then unarchived url response must be equal.")
+ XCTAssertEqual(responseA.mimeType, responseB.mimeType, "Archived then unarchived url response must be equal.")
+ XCTAssertEqual(responseA.expectedContentLength, responseB.expectedContentLength, "Archived then unarchived url response must be equal.")
+ XCTAssertEqual(responseA.textEncodingName, responseB.textEncodingName, "Archived then unarchived url response must be equal.")
+ XCTAssertEqual(responseA.suggestedFilename, responseB.suggestedFilename, "Archived then unarchived url response must be equal.")
+ }
}
@@ -127,6 +141,8 @@
("test_MIMETypeAndCharacterEncoding_1", test_MIMETypeAndCharacterEncoding_1),
("test_MIMETypeAndCharacterEncoding_2", test_MIMETypeAndCharacterEncoding_2),
("test_MIMETypeAndCharacterEncoding_3", test_MIMETypeAndCharacterEncoding_3),
+
+ ("test_NSCoding", test_NSCoding),
]
}
@@ -292,4 +308,28 @@
XCTAssertEqual(sut?.mimeType, "text/html")
XCTAssertEqual(sut?.textEncodingName, "iso-8859-4")
}
+
+ // NSCoding
+
+ func test_NSCoding() {
+ let url = URL(string: "https://apple.com")!
+ let f = ["Content-Type": "text/HTML; charset=ISO-8859-4"]
+
+ let responseA = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: f)!
+ let responseB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: responseA)) as! HTTPURLResponse
+
+ //On macOS unarchived Archived then unarchived `URLResponse` is not equal.
+ XCTAssertEqual(responseA.statusCode, responseB.statusCode, "Archived then unarchived http url response must be equal.")
+ XCTAssertEqual(Array(responseA.allHeaderFields.keys), Array(responseB.allHeaderFields.keys), "Archived then unarchived http url response must be equal.")
+
+ for key in responseA.allHeaderFields.keys {
+ XCTAssertEqual(responseA.allHeaderFields[key] as? String, responseB.allHeaderFields[key] as? String, "Archived then unarchived http url response must be equal.")
+ }
+
+ XCTAssertEqual(responseA.url, responseB.url, "Archived then unarchived http url response must be equal.")
+ XCTAssertEqual(responseA.mimeType, responseB.mimeType, "Archived then unarchived http url response must be equal.")
+ XCTAssertEqual(responseA.expectedContentLength, responseB.expectedContentLength, "Archived then unarchived http url response must be equal.")
+ XCTAssertEqual(responseA.textEncodingName, responseB.textEncodingName, "Archived then unarchived http url response must be equal.")
+ XCTAssertEqual(responseA.suggestedFilename, responseB.suggestedFilename, "Archived then unarchived http url response must be equal.")
+ }
}
diff --git a/TestFoundation/TestNSXMLDocument.swift b/TestFoundation/TestNSXMLDocument.swift
index a493dcd..c71ece6 100644
--- a/TestFoundation/TestNSXMLDocument.swift
+++ b/TestFoundation/TestNSXMLDocument.swift
@@ -13,7 +13,7 @@
import Foundation
import XCTest
#else
- @testable import SwiftFoundation
+ import SwiftFoundation
import SwiftXCTest
#endif
diff --git a/TestFoundation/TestNSXMLParser.swift b/TestFoundation/TestNSXMLParser.swift
index 486f23d..b181744 100644
--- a/TestFoundation/TestNSXMLParser.swift
+++ b/TestFoundation/TestNSXMLParser.swift
@@ -9,31 +9,146 @@
#if DEPLOYMENT_RUNTIME_OBJC || os(Linux)
-import Foundation
-import XCTest
+ import Foundation
+ import XCTest
#else
-import SwiftFoundation
-import SwiftXCTest
+ import SwiftFoundation
+ import SwiftXCTest
#endif
+class OptionalParserConformance: XMLParserDelegate {}
+
+enum XMLParserDelegateEvent {
+ case startDocument
+ case endDocument
+ case didStartElement(String, String?, String?, [String: String])
+ case didEndElement(String, String?, String?)
+ case foundCharacters(String)
+}
+
+extension XMLParserDelegateEvent: Equatable {
+
+ public static func ==(lhs: XMLParserDelegateEvent, rhs: XMLParserDelegateEvent) -> Bool {
+ switch (lhs, rhs) {
+ case (.startDocument, startDocument):
+ return true
+ case (.endDocument, endDocument):
+ return true
+ case let (.didStartElement(lhsElement, lhsNamespace, lhsQname, lhsAttr),
+ didStartElement(rhsElement, rhsNamespace, rhsQname, rhsAttr)):
+ return lhsElement == rhsElement && lhsNamespace == rhsNamespace && lhsQname == rhsQname && lhsAttr == rhsAttr
+ case let (.didEndElement(lhsElement, lhsNamespace, lhsQname),
+ .didEndElement(rhsElement, rhsNamespace, rhsQname)):
+ return lhsElement == rhsElement && lhsNamespace == rhsNamespace && lhsQname == rhsQname
+ case let (.foundCharacters(lhsChar), .foundCharacters(rhsChar)):
+ return lhsChar == rhsChar
+ default:
+ return false
+ }
+ }
+
+}
+
+class XMLParserDelegateEventStream: XMLParserDelegate {
+ var events: [XMLParserDelegateEvent] = []
+
+ func parserDidStartDocument(_ parser: XMLParser) {
+ events.append(.startDocument)
+ }
+ func parserDidEndDocument(_ parser: XMLParser) {
+ events.append(.endDocument)
+ }
+ func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
+ events.append(.didStartElement(elementName, namespaceURI, qName, attributeDict))
+ }
+ func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
+ events.append(.didEndElement(elementName, namespaceURI, qName))
+ }
+ func parser(_ parser: XMLParser, foundCharacters string: String) {
+ events.append(.foundCharacters(string))
+ }
+}
class TestNSXMLParser : XCTestCase {
-
+
static var allTests: [(String, (TestNSXMLParser) -> () throws -> Void)] {
return [
- ("test_data", test_data),
+ ("test_withData", test_withData),
+ ("test_withDataEncodings", test_withDataEncodings),
+ ("test_withDataOptions", test_withDataOptions),
]
}
-
- func test_data() {
- let xml = Array("<test><foo>bar</foo></test>".utf8CString)
+
+ // Helper method to embed the correct encoding in the XML header
+ static func xmlUnderTest(encoding: String.Encoding? = nil) -> String {
+ let xmlUnderTest = "<test attribute='value'><foo>bar</foo></test>"
+ guard var encoding = encoding?.description else {
+ return xmlUnderTest
+ }
+ if let open = encoding.range(of: "(") {
+ encoding = encoding.substring(from: open.upperBound)
+ }
+ if let close = encoding.range(of: ")") {
+ encoding = encoding.substring(to: close.lowerBound)
+ }
+ return "<?xml version='1.0' encoding='\(encoding.uppercased())' standalone='no'?>\n\(xmlUnderTest)\n"
+ }
+
+ static func xmlUnderTestExpectedEvents(namespaces: Bool = false) -> [XMLParserDelegateEvent] {
+ let uri: String? = namespaces ? "" : nil
+ return [
+ .startDocument,
+ .didStartElement("test", uri, namespaces ? "test" : nil, ["attribute": "value"]),
+ .didStartElement("foo", uri, namespaces ? "foo" : nil, [:]),
+ .foundCharacters("bar"),
+ .didEndElement("foo", uri, namespaces ? "foo" : nil),
+ .didEndElement("test", uri, namespaces ? "test" : nil),
+ ]
+ }
+
+
+ func test_withData() {
+ let xml = Array(TestNSXMLParser.xmlUnderTest().utf8CString)
let data = xml.withUnsafeBufferPointer { (buffer: UnsafeBufferPointer<CChar>) -> Data in
return buffer.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: buffer.count * MemoryLayout<CChar>.stride) {
return Data(bytes: $0, count: buffer.count)
}
}
let parser = XMLParser(data: data)
+ let stream = XMLParserDelegateEventStream()
+ parser.delegate = stream
let res = parser.parse()
+ XCTAssertEqual(stream.events, TestNSXMLParser.xmlUnderTestExpectedEvents())
XCTAssertTrue(res)
}
+
+ func test_withDataEncodings() {
+ // If th <?xml header isn't present, any non-UTF8 encodings fail. This appears to be libxml2 behavior.
+ // These don't work, it may just be an issue with the `encoding=xxx`.
+ // - .nextstep, .utf32LittleEndian
+ let encodings: [String.Encoding] = [.utf16LittleEndian, .utf16BigEndian, .utf32BigEndian, .ascii]
+ for encoding in encodings {
+ let xml = TestNSXMLParser.xmlUnderTest(encoding: encoding)
+ let parser = XMLParser(data: xml.data(using: encoding)!)
+ let stream = XMLParserDelegateEventStream()
+ parser.delegate = stream
+ let res = parser.parse()
+ XCTAssertEqual(stream.events, TestNSXMLParser.xmlUnderTestExpectedEvents())
+ XCTAssertTrue(res)
+ }
+ }
+
+ func test_withDataOptions() {
+ let xml = TestNSXMLParser.xmlUnderTest()
+ let parser = XMLParser(data: xml.data(using: String.Encoding.utf8)!)
+ parser.shouldProcessNamespaces = true
+ parser.shouldReportNamespacePrefixes = true
+ parser.shouldResolveExternalEntities = true
+ let stream = XMLParserDelegateEventStream()
+ parser.delegate = stream
+ let res = parser.parse()
+ XCTAssertEqual(stream.events, TestNSXMLParser.xmlUnderTestExpectedEvents(namespaces: true) )
+ XCTAssertTrue(res)
+ }
+
}