blob: 4ac4a1c5b7d50637acc13b9b19cabaeee1a5b8e1 [file] [log] [blame]
//===--- 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<T>(_ value: AnyObject, to: T.Type) -> T {
return value as! T
}
// expectEqual() helpers for deeper-nested nullability than StdlibUnittest
// provides.
func expectEqual<T: Equatable>(_ 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<T: Equatable>(_ 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<String>.self)
let doubleWrappedCastBack = cast(doubleWrappedBridged, to: Optional<String?>.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<NotBridged>.self)
let doubleWrappedCastBack = cast(doubleWrappedBridged, to: Optional<NotBridged?>.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<String>.self)
let wrappedNullCastBack = cast(nullBridged, to: Optional<String?>.self)
let doubleWrappedNullCastBack = cast(nullBridged, to: Optional<String??>.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<String?>.self)
let wrappedDoubleNullCastBack = cast(doubleNullBridged, to: Optional<String??>.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<String??>.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()