//===--- OptionalBridge.swift - Tests of Optional bridging ----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // RUN: %target-run-simple-swift // REQUIRES: executable_test // REQUIRES: objc_interop import Foundation import StdlibUnittest let tests = TestSuite("OptionalBridge") // Work around bugs in the type checker preventing casts back to optional. func cast(_ value: AnyObject, to: T.Type) -> T { return value as! T } // expectEqual() helpers for deeper-nested nullability than StdlibUnittest // provides. func expectEqual(_ x: T??, _ y: T??) { switch (x, y) { case (.some(let xx), .some(let yy)): expectEqual(xx, yy) case (.none, .none): return default: expectUnreachable("\(T.self)?? values don't match: \(x) vs. \(y)") } } func expectEqual(_ x: T???, _ y: T???) { switch (x, y) { case (.some(let xx), .some(let yy)): expectEqual(xx, yy) case (.none, .none): return default: expectUnreachable("\(T.self)??? values don't match: \(x) vs. \(y)") } } tests.test("wrapped value") { let unwrapped = "foo" let wrapped = Optional(unwrapped) let doubleWrapped = Optional(wrapped) let unwrappedBridged = unwrapped as AnyObject let wrappedBridged = wrapped as AnyObject let doubleWrappedBridged = doubleWrapped as AnyObject expectTrue(unwrappedBridged.isEqual(wrappedBridged) && wrappedBridged.isEqual(doubleWrappedBridged)) let unwrappedCastBack = cast(unwrappedBridged, to: String.self) let wrappedCastBack = cast(wrappedBridged, to: Optional.self) let doubleWrappedCastBack = cast(doubleWrappedBridged, to: Optional.self) expectEqual(unwrapped, unwrappedCastBack) expectEqual(wrapped, wrappedCastBack) expectEqual(doubleWrapped, doubleWrappedCastBack) } struct NotBridged: Hashable { var x: Int func hash(into hasher: inout Hasher) { hasher.combine(x) } static func ==(x: NotBridged, y: NotBridged) -> Bool { return x.x == y.x } } tests.test("wrapped boxed value") { let unwrapped = NotBridged(x: 1738) let wrapped = Optional(unwrapped) let doubleWrapped = Optional(wrapped) let unwrappedBridged = unwrapped as AnyObject let wrappedBridged = wrapped as AnyObject let doubleWrappedBridged = doubleWrapped as AnyObject expectTrue(unwrappedBridged.isEqual(wrappedBridged)) expectTrue(wrappedBridged.isEqual(doubleWrappedBridged)) let unwrappedCastBack = cast(unwrappedBridged, to: NotBridged.self) let wrappedCastBack = cast(wrappedBridged, to: Optional.self) let doubleWrappedCastBack = cast(doubleWrappedBridged, to: Optional.self) expectEqual(unwrapped, unwrappedCastBack) expectEqual(wrapped, wrappedCastBack) expectEqual(doubleWrapped, doubleWrappedCastBack) } tests.test("wrapped class instance") { let unwrapped = LifetimeTracked(0) let wrapped = Optional(unwrapped) expectTrue(wrapped as AnyObject === unwrapped as AnyObject) } tests.test("nil") { let null: String? = nil let wrappedNull = Optional(null) let doubleWrappedNull = Optional(wrappedNull) let nullBridged = null as AnyObject let wrappedNullBridged = wrappedNull as AnyObject let doubleWrappedNullBridged = doubleWrappedNull as AnyObject expectTrue(nullBridged === NSNull()) expectTrue(wrappedNullBridged === NSNull()) expectTrue(doubleWrappedNullBridged === NSNull()) let nullCastBack = cast(nullBridged, to: Optional.self) let wrappedNullCastBack = cast(nullBridged, to: Optional.self) let doubleWrappedNullCastBack = cast(nullBridged, to: Optional.self) expectEqual(nullCastBack, null) expectEqual(wrappedNullCastBack, wrappedNull) expectEqual(doubleWrappedNullCastBack, doubleWrappedNull) } tests.test("nil in nested optional") { let doubleNull: String?? = nil let wrappedDoubleNull = Optional(doubleNull) let doubleNullBridged = doubleNull as AnyObject let wrappedDoubleNullBridged = wrappedDoubleNull as AnyObject expectTrue(doubleNullBridged === wrappedDoubleNullBridged) expectTrue(doubleNullBridged !== NSNull()) let doubleNullCastBack = cast(doubleNullBridged, to: Optional.self) let wrappedDoubleNullCastBack = cast(doubleNullBridged, to: Optional.self) expectEqual(doubleNullCastBack, doubleNull) expectEqual(wrappedDoubleNullCastBack, wrappedDoubleNull) let tripleNull: String??? = nil let tripleNullBridged = tripleNull as AnyObject expectTrue(doubleNullBridged !== tripleNullBridged) let tripleNullCastBack = cast(tripleNullBridged, to: Optional.self) expectEqual(tripleNullCastBack, tripleNull) } tests.test("collection of Optional") { let holeyArray: [LifetimeTracked?] = [LifetimeTracked(0), nil, LifetimeTracked(1)] let nsArray = holeyArray as NSArray autoreleasepool { expectTrue((nsArray[0] as AnyObject) === holeyArray[0]!) expectTrue((nsArray[1] as AnyObject) === NSNull()) expectTrue((nsArray[2] as AnyObject) === holeyArray[2]!) } } tests.test("NSArray of NSNull") { let holeyNSArray: NSArray = [LifetimeTracked(2), NSNull(), LifetimeTracked(3)] autoreleasepool { let swiftArray = holeyNSArray as! [LifetimeTracked?] expectTrue(swiftArray[0]! === holeyNSArray[0] as AnyObject) expectTrue(swiftArray[1] == nil) expectTrue(swiftArray[2]! === holeyNSArray[2] as AnyObject) } } runAllTests()