mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
706 lines
21 KiB
Swift
706 lines
21 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: objc_interop
|
|
|
|
import StdlibUnittest
|
|
|
|
|
|
import Foundation
|
|
import CoreLocation
|
|
import Darwin
|
|
|
|
var ErrorBridgingTests = TestSuite("ErrorBridging")
|
|
|
|
var NoisyErrorLifeCount = 0
|
|
var NoisyErrorDeathCount = 0
|
|
var CanaryHandle = 0
|
|
|
|
protocol OtherProtocol {
|
|
var otherProperty: String { get }
|
|
}
|
|
|
|
protocol OtherClassProtocol : class {
|
|
var otherClassProperty: String { get }
|
|
}
|
|
|
|
class NoisyError : Error, OtherProtocol, OtherClassProtocol {
|
|
init() { NoisyErrorLifeCount += 1 }
|
|
deinit { NoisyErrorDeathCount += 1 }
|
|
|
|
let _domain = "NoisyError"
|
|
let _code = 123
|
|
|
|
let otherProperty = "otherProperty"
|
|
let otherClassProperty = "otherClassProperty"
|
|
}
|
|
|
|
@objc enum EnumError : Int, Error {
|
|
case BadError = 9000
|
|
case ReallyBadError = 9001
|
|
}
|
|
|
|
ErrorBridgingTests.test("NSError") {
|
|
NoisyErrorLifeCount = 0
|
|
NoisyErrorDeathCount = 0
|
|
autoreleasepool {
|
|
let ns = NSError(domain: "SomeDomain", code: 321, userInfo: nil)
|
|
|
|
objc_setAssociatedObject(ns, &CanaryHandle, NoisyError(),
|
|
.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
|
|
let e: Error = ns
|
|
expectEqual(e._domain, "SomeDomain")
|
|
expectEqual(e._code, 321)
|
|
|
|
let ns2 = e as NSError
|
|
expectTrue(ns === ns2)
|
|
expectEqual(ns2._domain, "SomeDomain")
|
|
expectEqual(ns2._code, 321)
|
|
}
|
|
expectEqual(NoisyErrorDeathCount, NoisyErrorLifeCount)
|
|
}
|
|
|
|
ErrorBridgingTests.test("NSCopying") {
|
|
autoreleasepool {
|
|
let orig = EnumError.ReallyBadError as NSError
|
|
let copy = orig.copy() as! NSError
|
|
expectEqual(orig, copy)
|
|
}
|
|
}
|
|
|
|
func archiveAndUnarchiveObject<T: NSCoding>(
|
|
_ object: T
|
|
) -> T?
|
|
where T: NSObject {
|
|
let unarchiver = NSKeyedUnarchiver(forReadingWith:
|
|
NSKeyedArchiver.archivedData(withRootObject: object)
|
|
)
|
|
unarchiver.requiresSecureCoding = true
|
|
return unarchiver.decodeObject(of: T.self, forKey: "root")
|
|
}
|
|
ErrorBridgingTests.test("NSCoding") {
|
|
autoreleasepool {
|
|
let orig = EnumError.ReallyBadError as NSError
|
|
let unarchived = archiveAndUnarchiveObject(orig)!
|
|
expectEqual(orig, unarchived)
|
|
expectTrue(type(of: unarchived) == NSError.self)
|
|
}
|
|
}
|
|
|
|
ErrorBridgingTests.test("NSError-to-enum bridging") {
|
|
NoisyErrorLifeCount = 0
|
|
NoisyErrorDeathCount = 0
|
|
let testURL = URL(string: "https://swift.org")!
|
|
|
|
autoreleasepool {
|
|
let underlyingError = CocoaError(.fileLockingError)
|
|
as Error as NSError
|
|
let ns = NSError(domain: NSCocoaErrorDomain,
|
|
code: NSFileNoSuchFileError,
|
|
userInfo: [
|
|
AnyHashable(NSFilePathErrorKey): "/dev/null",
|
|
AnyHashable(NSStringEncodingErrorKey): /*ASCII=*/1,
|
|
AnyHashable(NSUnderlyingErrorKey): underlyingError,
|
|
AnyHashable(NSURLErrorKey): testURL
|
|
])
|
|
|
|
objc_setAssociatedObject(ns, &CanaryHandle, NoisyError(),
|
|
.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
|
|
let e: Error = ns
|
|
|
|
let cocoaCode: Int?
|
|
switch e {
|
|
case let x as CocoaError:
|
|
cocoaCode = x._code
|
|
expectTrue(x.isFileError)
|
|
expectEqual(x.code, CocoaError.fileNoSuchFileError)
|
|
default:
|
|
cocoaCode = nil
|
|
}
|
|
|
|
expectEqual(NSFileNoSuchFileError, cocoaCode)
|
|
|
|
let cocoaCode2: Int? = (ns as? CocoaError)?._code
|
|
expectEqual(NSFileNoSuchFileError, cocoaCode2)
|
|
|
|
let isNoSuchFileError: Bool
|
|
switch e {
|
|
case CocoaError.fileNoSuchFileError:
|
|
isNoSuchFileError = true
|
|
default:
|
|
isNoSuchFileError = false
|
|
}
|
|
|
|
expectTrue(isNoSuchFileError)
|
|
|
|
// Check the contents of the error.
|
|
let cocoaError = e as! CocoaError
|
|
expectOptionalEqual("/dev/null", cocoaError.filePath)
|
|
expectOptionalEqual(String.Encoding.ascii, cocoaError.stringEncoding)
|
|
expectOptionalEqual(underlyingError, cocoaError.underlying.map { $0 as NSError })
|
|
expectOptionalEqual(testURL, cocoaError.url)
|
|
|
|
// URLError domain
|
|
let nsURL = NSError(domain: NSURLErrorDomain,
|
|
code: NSURLErrorBadURL,
|
|
userInfo: [AnyHashable(NSURLErrorFailingURLErrorKey): testURL])
|
|
let eURL: Error = nsURL
|
|
let isBadURLError: Bool
|
|
switch eURL {
|
|
case URLError.badURL:
|
|
isBadURLError = true
|
|
default:
|
|
isBadURLError = false
|
|
}
|
|
|
|
expectTrue(isBadURLError)
|
|
|
|
let urlError = eURL as! URLError
|
|
expectOptionalEqual(testURL, urlError.failingURL)
|
|
expectNil(urlError.failureURLPeerTrust)
|
|
|
|
// CoreLocation error domain
|
|
let nsCL = NSError(domain: kCLErrorDomain,
|
|
code: CLError.headingFailure.rawValue,
|
|
userInfo: [AnyHashable(NSURLErrorKey): testURL])
|
|
let eCL: Error = nsCL
|
|
let isHeadingFailure: Bool
|
|
switch eCL {
|
|
case CLError.headingFailure:
|
|
isHeadingFailure = true
|
|
default:
|
|
isHeadingFailure = false
|
|
}
|
|
|
|
let isCLError: Bool
|
|
switch eCL {
|
|
case let error as CLError:
|
|
isCLError = true
|
|
expectOptionalEqual(testURL, (error as NSError).userInfo[NSURLErrorKey as NSObject] as? URL)
|
|
expectOptionalEqual(testURL, error.userInfo[NSURLErrorKey] as? URL)
|
|
default:
|
|
isCLError = false
|
|
}
|
|
|
|
expectTrue(isCLError)
|
|
|
|
// NSPOSIXError domain
|
|
let nsPOSIX = NSError(domain: NSPOSIXErrorDomain,
|
|
code: Int(EDEADLK),
|
|
userInfo: [:])
|
|
let ePOSIX: Error = nsPOSIX
|
|
let isDeadlock: Bool
|
|
switch ePOSIX {
|
|
case POSIXError.EDEADLK:
|
|
isDeadlock = true
|
|
default:
|
|
isDeadlock = false
|
|
}
|
|
|
|
expectTrue(isDeadlock)
|
|
|
|
// NSMachError domain
|
|
let nsMach = NSError(domain: NSMachErrorDomain,
|
|
code: Int(KERN_MEMORY_FAILURE),
|
|
userInfo: [:])
|
|
let eMach: Error = nsMach
|
|
let isMemoryFailure: Bool
|
|
switch eMach {
|
|
case MachError.memoryFailure:
|
|
isMemoryFailure = true
|
|
default:
|
|
isMemoryFailure = false
|
|
}
|
|
|
|
expectTrue(isMemoryFailure)
|
|
}
|
|
|
|
expectEqual(NoisyErrorDeathCount, NoisyErrorLifeCount)
|
|
}
|
|
|
|
func opaqueUpcastToAny<T>(_ x: T) -> Any {
|
|
return x
|
|
}
|
|
|
|
struct StructError: Error {
|
|
var _domain: String { return "StructError" }
|
|
var _code: Int { return 4812 }
|
|
}
|
|
|
|
ErrorBridgingTests.test("Error-to-NSError bridging") {
|
|
NoisyErrorLifeCount = 0
|
|
NoisyErrorDeathCount = 0
|
|
autoreleasepool {
|
|
let e: Error = NoisyError()
|
|
let ns = e as NSError
|
|
let ns2 = e as NSError
|
|
expectTrue(ns === ns2)
|
|
expectEqual(ns._domain, "NoisyError")
|
|
expectEqual(ns._code, 123)
|
|
|
|
let e3: Error = ns
|
|
expectEqual(e3._domain, "NoisyError")
|
|
expectEqual(e3._code, 123)
|
|
let ns3 = e3 as NSError
|
|
expectTrue(ns === ns3)
|
|
|
|
let nativeNS = NSError(domain: NSCocoaErrorDomain,
|
|
code: NSFileNoSuchFileError,
|
|
userInfo: nil)
|
|
|
|
objc_setAssociatedObject(ns, &CanaryHandle, NoisyError(),
|
|
.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
|
|
|
let nativeE: Error = nativeNS
|
|
let nativeNS2 = nativeE as NSError
|
|
expectTrue(nativeNS === nativeNS2)
|
|
expectEqual(nativeNS2._domain, NSCocoaErrorDomain)
|
|
expectEqual(nativeNS2._code, NSFileNoSuchFileError)
|
|
|
|
let any: Any = NoisyError()
|
|
let ns4 = any as! NSError
|
|
expectEqual(ns4._domain, "NoisyError")
|
|
expectEqual(ns4._code, 123)
|
|
|
|
let ao: AnyObject = NoisyError()
|
|
let ns5 = ao as! NSError
|
|
expectEqual(ns5._domain, "NoisyError")
|
|
expectEqual(ns5._code, 123)
|
|
|
|
let any2: Any = StructError()
|
|
let ns6 = any2 as! NSError
|
|
expectEqual(ns6._domain, "StructError")
|
|
expectEqual(ns6._code, 4812)
|
|
}
|
|
expectEqual(NoisyErrorDeathCount, NoisyErrorLifeCount)
|
|
}
|
|
|
|
ErrorBridgingTests.test("enum-to-NSError round trip") {
|
|
autoreleasepool {
|
|
// Emulate throwing an error from Objective-C.
|
|
func throwNSError(_ error: EnumError) throws {
|
|
throw NSError(domain: "main.EnumError", code: error.rawValue,
|
|
userInfo: [:])
|
|
}
|
|
|
|
var caughtError: Bool
|
|
|
|
caughtError = false
|
|
do {
|
|
try throwNSError(.BadError)
|
|
expectUnreachable()
|
|
} catch let error as EnumError {
|
|
expectEqual(.BadError, error)
|
|
caughtError = true
|
|
} catch _ {
|
|
expectUnreachable()
|
|
}
|
|
expectTrue(caughtError)
|
|
|
|
caughtError = false
|
|
do {
|
|
try throwNSError(.ReallyBadError)
|
|
expectUnreachable()
|
|
} catch EnumError.BadError {
|
|
expectUnreachable()
|
|
} catch EnumError.ReallyBadError {
|
|
caughtError = true
|
|
} catch _ {
|
|
expectUnreachable()
|
|
}
|
|
expectTrue(caughtError)
|
|
}
|
|
}
|
|
|
|
class SomeNSErrorSubclass: NSError {}
|
|
|
|
|
|
ErrorBridgingTests.test("Thrown NSError identity is preserved") {
|
|
do {
|
|
let e = NSError(domain: "ClericalError", code: 219,
|
|
userInfo: [AnyHashable("yeah"): "yeah"])
|
|
do {
|
|
throw e
|
|
} catch let e2 as NSError {
|
|
expectTrue(e === e2)
|
|
expectTrue(e2.userInfo["yeah"] as? String == "yeah")
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
}
|
|
|
|
do {
|
|
let f = SomeNSErrorSubclass(domain: "ClericalError", code: 219,
|
|
userInfo: [AnyHashable("yeah"): "yeah"])
|
|
do {
|
|
throw f
|
|
} catch let f2 as NSError {
|
|
expectTrue(f === f2)
|
|
expectTrue(f2.userInfo["yeah"] as? String == "yeah")
|
|
} catch {
|
|
expectUnreachable()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check errors customized via protocol.
|
|
struct MyCustomizedError : Error {
|
|
let code: Int
|
|
}
|
|
|
|
extension MyCustomizedError : LocalizedError {
|
|
var errorDescription: String? {
|
|
return NSLocalizedString("something went horribly wrong", comment: "")
|
|
}
|
|
|
|
var failureReason: String? {
|
|
return NSLocalizedString("because someone wrote 'throw'", comment: "")
|
|
}
|
|
|
|
var recoverySuggestion: String? {
|
|
return NSLocalizedString("delete the 'throw'", comment: "")
|
|
}
|
|
|
|
var helpAnchor: String? {
|
|
return NSLocalizedString("there is no help when writing tests", comment: "")
|
|
}
|
|
}
|
|
|
|
extension MyCustomizedError : CustomNSError {
|
|
static var errorDomain: String {
|
|
return "custom"
|
|
}
|
|
|
|
/// The error code within the given domain.
|
|
var errorCode: Int {
|
|
return code
|
|
}
|
|
|
|
/// The user-info dictionary.
|
|
var errorUserInfo: [String : Any] {
|
|
return [NSURLErrorKey : URL(string: "https://swift.org")!]
|
|
}
|
|
}
|
|
|
|
extension MyCustomizedError : RecoverableError {
|
|
var recoveryOptions: [String] {
|
|
return ["Delete 'throw'", "Disable the test" ]
|
|
}
|
|
|
|
func attemptRecovery(optionIndex recoveryOptionIndex: Int) -> Bool {
|
|
return recoveryOptionIndex == 0
|
|
}
|
|
}
|
|
|
|
/// An error type that provides localization and recovery, but doesn't
|
|
/// customize NSError directly.
|
|
enum MySwiftCustomizedError : Error {
|
|
case failed
|
|
static var errorDescriptionCount = 0
|
|
}
|
|
|
|
extension MySwiftCustomizedError : LocalizedError {
|
|
var errorDescription: String? {
|
|
MySwiftCustomizedError.errorDescriptionCount =
|
|
MySwiftCustomizedError.errorDescriptionCount + 1
|
|
return NSLocalizedString("something went horribly wrong", comment: "")
|
|
}
|
|
|
|
var failureReason: String? {
|
|
return NSLocalizedString("because someone wrote 'throw'", comment: "")
|
|
}
|
|
|
|
var recoverySuggestion: String? {
|
|
return NSLocalizedString("delete the 'throw'", comment: "")
|
|
}
|
|
|
|
var helpAnchor: String? {
|
|
return NSLocalizedString("there is no help when writing tests", comment: "")
|
|
}
|
|
}
|
|
|
|
extension MySwiftCustomizedError : RecoverableError {
|
|
var recoveryOptions: [String] {
|
|
return ["Delete 'throw'", "Disable the test" ]
|
|
}
|
|
|
|
func attemptRecovery(optionIndex recoveryOptionIndex: Int) -> Bool {
|
|
return recoveryOptionIndex == 0
|
|
}
|
|
}
|
|
|
|
/// Fake definition of the informal protocol
|
|
/// "NSErrorRecoveryAttempting" that we use to poke at the object
|
|
/// produced for a RecoverableError.
|
|
@objc protocol FakeNSErrorRecoveryAttempting {
|
|
@objc(attemptRecoveryFromError:optionIndex:delegate:didRecoverSelector:contextInfo:)
|
|
func attemptRecovery(fromError nsError: Error,
|
|
optionIndex recoveryOptionIndex: Int,
|
|
delegate: AnyObject?,
|
|
didRecoverSelector: Selector,
|
|
contextInfo: UnsafeMutableRawPointer?)
|
|
|
|
@objc(attemptRecoveryFromError:optionIndex:)
|
|
func attemptRecovery(fromError nsError: Error,
|
|
optionIndex recoveryOptionIndex: Int) -> Bool
|
|
}
|
|
|
|
class RecoveryDelegate {
|
|
let expectedSuccess: Bool
|
|
let expectedContextInfo: UnsafeMutableRawPointer?
|
|
var called = false
|
|
|
|
init(expectedSuccess: Bool,
|
|
expectedContextInfo: UnsafeMutableRawPointer?) {
|
|
self.expectedSuccess = expectedSuccess
|
|
self.expectedContextInfo = expectedContextInfo
|
|
}
|
|
|
|
@objc func recover(success: Bool, contextInfo: UnsafeMutableRawPointer?) {
|
|
expectEqual(expectedSuccess, success)
|
|
expectEqual(expectedContextInfo, contextInfo)
|
|
called = true
|
|
}
|
|
}
|
|
|
|
/// Helper for testing a customized error.
|
|
func testCustomizedError(error: Error, nsError: NSError) {
|
|
// LocalizedError
|
|
if #available(OSX 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
|
|
expectNil(nsError.userInfo[NSLocalizedDescriptionKey as NSObject])
|
|
expectNil(nsError.userInfo[NSLocalizedFailureReasonErrorKey as NSObject])
|
|
expectNil(nsError.userInfo[NSLocalizedRecoverySuggestionErrorKey as NSObject])
|
|
expectNil(nsError.userInfo[NSHelpAnchorErrorKey as NSObject])
|
|
} else {
|
|
expectOptionalEqual("something went horribly wrong",
|
|
nsError.userInfo[NSLocalizedDescriptionKey as NSObject] as? String)
|
|
expectOptionalEqual("because someone wrote 'throw'",
|
|
nsError.userInfo[NSLocalizedFailureReasonErrorKey as NSObject] as? String)
|
|
expectOptionalEqual("delete the 'throw'",
|
|
nsError.userInfo[NSLocalizedRecoverySuggestionErrorKey as NSObject] as? String)
|
|
expectOptionalEqual("there is no help when writing tests",
|
|
nsError.userInfo[NSHelpAnchorErrorKey as NSObject] as? String)
|
|
}
|
|
expectEqual("something went horribly wrong", error.localizedDescription)
|
|
expectEqual("something went horribly wrong", nsError.localizedDescription)
|
|
expectEqual("because someone wrote 'throw'", nsError.localizedFailureReason)
|
|
expectEqual("delete the 'throw'", nsError.localizedRecoverySuggestion)
|
|
expectEqual("there is no help when writing tests", nsError.helpAnchor)
|
|
|
|
// RecoverableError
|
|
if #available(OSX 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
|
|
expectNil(nsError.userInfo[NSLocalizedRecoveryOptionsErrorKey as NSObject])
|
|
} else {
|
|
expectOptionalEqual(["Delete 'throw'", "Disable the test" ],
|
|
nsError.userInfo[NSLocalizedRecoveryOptionsErrorKey as NSObject] as? [String])
|
|
}
|
|
expectOptionalEqual(["Delete 'throw'", "Disable the test" ],
|
|
nsError.localizedRecoveryOptions)
|
|
|
|
// Directly recover.
|
|
let ctx = UnsafeMutableRawPointer(bitPattern:0x1234567)
|
|
let attempter: AnyObject
|
|
if #available(OSX 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
|
|
expectNil(nsError.userInfo[NSRecoveryAttempterErrorKey as NSObject])
|
|
attempter = nsError.recoveryAttempter! as AnyObject
|
|
} else {
|
|
attempter = nsError.userInfo[NSRecoveryAttempterErrorKey as NSObject]! as AnyObject
|
|
}
|
|
expectOptionalEqual(attempter.attemptRecovery(fromError: nsError,
|
|
optionIndex: 0),
|
|
true)
|
|
expectOptionalEqual(attempter.attemptRecovery(fromError: nsError,
|
|
optionIndex: 1),
|
|
false)
|
|
|
|
// Recover through delegate.
|
|
let rd1 = RecoveryDelegate(expectedSuccess: true, expectedContextInfo: ctx)
|
|
expectEqual(false, rd1.called)
|
|
attempter.attemptRecovery(
|
|
fromError: nsError,
|
|
optionIndex: 0,
|
|
delegate: rd1,
|
|
didRecoverSelector: #selector(RecoveryDelegate.recover(success:contextInfo:)),
|
|
contextInfo: ctx)
|
|
expectEqual(true, rd1.called)
|
|
|
|
let rd2 = RecoveryDelegate(expectedSuccess: false, expectedContextInfo: nil)
|
|
expectEqual(false, rd2.called)
|
|
attempter.attemptRecovery(
|
|
fromError: nsError,
|
|
optionIndex: 1,
|
|
delegate: rd2,
|
|
didRecoverSelector: #selector(RecoveryDelegate.recover(success:contextInfo:)),
|
|
contextInfo: nil)
|
|
expectEqual(true, rd2.called)
|
|
}
|
|
|
|
ErrorBridgingTests.test("Customizing NSError via protocols") {
|
|
let error = MyCustomizedError(code: 12345)
|
|
let nsError = error as NSError
|
|
|
|
// CustomNSError
|
|
expectEqual("custom", nsError.domain)
|
|
expectEqual(12345, nsError.code)
|
|
expectOptionalEqual(URL(string: "https://swift.org")!,
|
|
nsError.userInfo[NSURLErrorKey as NSObject] as? URL)
|
|
|
|
testCustomizedError(error: error, nsError: nsError)
|
|
}
|
|
|
|
ErrorBridgingTests.test("Customizing localization/recovery via protocols") {
|
|
let error = MySwiftCustomizedError.failed
|
|
let nsError = error as NSError
|
|
testCustomizedError(error: error, nsError: nsError)
|
|
}
|
|
|
|
ErrorBridgingTests.test("Customizing localization/recovery laziness") {
|
|
let countBefore = MySwiftCustomizedError.errorDescriptionCount
|
|
let error = MySwiftCustomizedError.failed
|
|
let nsError = error as NSError
|
|
|
|
// RecoverableError
|
|
if #available(OSX 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
|
|
expectNil(nsError.userInfo[NSLocalizedRecoveryOptionsErrorKey as NSObject])
|
|
} else {
|
|
expectOptionalEqual(["Delete 'throw'", "Disable the test" ],
|
|
nsError.userInfo[NSLocalizedRecoveryOptionsErrorKey as NSObject] as? [String])
|
|
}
|
|
expectOptionalEqual(["Delete 'throw'", "Disable the test" ],
|
|
nsError.localizedRecoveryOptions)
|
|
|
|
// None of the operations above should affect the count
|
|
if #available(OSX 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
|
|
expectEqual(countBefore, MySwiftCustomizedError.errorDescriptionCount)
|
|
}
|
|
|
|
// This one does affect the count.
|
|
expectEqual("something went horribly wrong", error.localizedDescription)
|
|
|
|
// Check that we did get a call to errorDescription.
|
|
if #available(OSX 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
|
|
expectEqual(countBefore+1, MySwiftCustomizedError.errorDescriptionCount)
|
|
}
|
|
}
|
|
|
|
enum DefaultCustomizedError1 : CustomNSError {
|
|
case bad
|
|
case worse
|
|
}
|
|
|
|
enum DefaultCustomizedError2 : Int, CustomNSError {
|
|
case bad = 7
|
|
case worse = 13
|
|
}
|
|
|
|
enum DefaultCustomizedError3 : UInt, CustomNSError {
|
|
case bad = 9
|
|
case worse = 115
|
|
|
|
static var errorDomain: String {
|
|
return "customized3"
|
|
}
|
|
}
|
|
|
|
enum DefaultCustomizedParent {
|
|
enum ChildError: CustomNSError {
|
|
case foo
|
|
}
|
|
}
|
|
|
|
ErrorBridgingTests.test("Default-customized via CustomNSError") {
|
|
expectEqual(1, (DefaultCustomizedError1.worse as NSError).code)
|
|
expectEqual(13, (DefaultCustomizedError2.worse as NSError).code)
|
|
expectEqual(115, (DefaultCustomizedError3.worse as NSError).code)
|
|
expectEqual("main.DefaultCustomizedError1", (DefaultCustomizedError1.worse as NSError).domain)
|
|
expectEqual("customized3", (DefaultCustomizedError3.worse as NSError).domain)
|
|
expectEqual("main.DefaultCustomizedParent.ChildError", (DefaultCustomizedParent.ChildError.foo as NSError).domain)
|
|
}
|
|
|
|
class MyNSError : NSError { }
|
|
|
|
ErrorBridgingTests.test("NSError subclass identity") {
|
|
let myNSError: Error = MyNSError(domain: "MyNSError", code: 0, userInfo: [:])
|
|
let nsError = myNSError as NSError
|
|
expectTrue(type(of: nsError) == MyNSError.self)
|
|
}
|
|
|
|
ErrorBridgingTests.test("Wrapped NSError identity") {
|
|
let nsError = NSError(domain: NSCocoaErrorDomain,
|
|
code: NSFileNoSuchFileError,
|
|
userInfo: [
|
|
AnyHashable(NSFilePathErrorKey) : "/dev/null",
|
|
AnyHashable(NSStringEncodingErrorKey): /*ASCII=*/1,
|
|
])
|
|
|
|
let error: Error = nsError
|
|
let nsError2: NSError = error as NSError
|
|
expectTrue(nsError === nsError2)
|
|
|
|
// Extracting the NSError via the runtime.
|
|
let cocoaErrorAny: Any = error as! CocoaError
|
|
let nsError3: NSError = cocoaErrorAny as! NSError
|
|
expectTrue(nsError === nsError3)
|
|
|
|
if let cocoaErrorAny2: Any = error as? CocoaError {
|
|
let nsError4: NSError = cocoaErrorAny2 as! NSError
|
|
expectTrue(nsError === nsError4)
|
|
} else {
|
|
expectUnreachable()
|
|
}
|
|
|
|
// Extracting the NSError via direct call.
|
|
let cocoaError = error as! CocoaError
|
|
let nsError5: NSError = cocoaError as NSError
|
|
expectTrue(nsError === nsError5)
|
|
|
|
if let cocoaError2 = error as? CocoaError {
|
|
let nsError6: NSError = cocoaError as NSError
|
|
expectTrue(nsError === nsError6)
|
|
} else {
|
|
expectUnreachable()
|
|
}
|
|
}
|
|
|
|
extension Error {
|
|
func asNSError() -> NSError {
|
|
return self as NSError
|
|
}
|
|
}
|
|
|
|
func unconditionalCast<T>(_ x: Any, to: T.Type) -> T {
|
|
return x as! T
|
|
}
|
|
|
|
func conditionalCast<T>(_ x: Any, to: T.Type) -> T? {
|
|
return x as? T
|
|
}
|
|
|
|
// SR-1562
|
|
ErrorBridgingTests.test("Error archetype identity") {
|
|
let myError = NSError(domain: "myErrorDomain", code: 0,
|
|
userInfo: [ AnyHashable("one") : 1 ])
|
|
expectTrue(myError === myError.asNSError())
|
|
|
|
expectTrue(unconditionalCast(myError, to: Error.self) as NSError
|
|
=== myError)
|
|
expectTrue(conditionalCast(myError, to: Error.self)! as NSError
|
|
=== myError)
|
|
|
|
let nsError = NSError(domain: NSCocoaErrorDomain,
|
|
code: NSFileNoSuchFileError,
|
|
userInfo: [
|
|
AnyHashable(NSFilePathErrorKey) : "/dev/null",
|
|
AnyHashable(NSStringEncodingErrorKey): /*ASCII=*/1,
|
|
])
|
|
let cocoaError = nsError as Error as! CocoaError
|
|
expectTrue(cocoaError.asNSError() === nsError)
|
|
expectTrue(unconditionalCast(cocoaError, to: Error.self) as NSError
|
|
=== nsError)
|
|
expectTrue(conditionalCast(cocoaError, to: Error.self)! as NSError
|
|
=== nsError)
|
|
}
|
|
|
|
runAllTests()
|