mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
336 lines
9.4 KiB
Swift
336 lines
9.4 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
|
|
import StdlibUnittest
|
|
import Swift
|
|
|
|
// Also import modules which are used by StdlibUnittest internally. This
|
|
// workaround is needed to link all required libraries in case we compile
|
|
// StdlibUnittest with -sil-serialize-all.
|
|
import SwiftPrivate
|
|
#if _runtime(_ObjC)
|
|
import ObjectiveC
|
|
#endif
|
|
|
|
class DeinitTester {
|
|
private let onDeinit: () -> ()
|
|
|
|
init(onDeinit: () -> ()) {
|
|
self.onDeinit = onDeinit
|
|
}
|
|
deinit {
|
|
onDeinit()
|
|
}
|
|
}
|
|
|
|
let OptionalTests = TestSuite("Optional")
|
|
|
|
protocol TestProtocol1 {}
|
|
|
|
// Check the generic parameter name.
|
|
extension Optional where Wrapped : TestProtocol1 {
|
|
var _wrappedIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
extension ImplicitlyUnwrappedOptional where Wrapped : TestProtocol1 {
|
|
var _wrappedIsTestProtocol1: Bool {
|
|
fatalError("not implemented")
|
|
}
|
|
}
|
|
|
|
OptionalTests.test("nil comparison") {
|
|
var x: Int? = nil
|
|
expectFalse(x != nil)
|
|
|
|
switch x {
|
|
case .some(let y): expectUnreachable()
|
|
case .none: break
|
|
}
|
|
|
|
x = .some(1)
|
|
expectTrue(x != nil)
|
|
|
|
if true {
|
|
var y1: Int? = .none
|
|
expectTrue(y1 == nil)
|
|
|
|
var y2: Int? = .none
|
|
expectTrue(y2 == nil)
|
|
}
|
|
|
|
let x1: Int? = nil
|
|
let x2: Int? = .none
|
|
|
|
expectTrue(x1 == nil)
|
|
expectTrue(x2 == nil)
|
|
|
|
switch x {
|
|
case .some(let y): expectEqual("1", "\(y)")
|
|
case .none: assert(false)
|
|
}
|
|
|
|
expectEqual("forced extraction: 1.", "forced extraction: \(x!).")
|
|
expectEqual("forced extraction use: 2.", "forced extraction use: \(x!.successor()).")
|
|
}
|
|
|
|
func testRelation(p: (Int?, Int?) -> Bool) -> [Bool] {
|
|
typealias optPair = (Int?, Int?)
|
|
|
|
let relationships: [optPair] = [
|
|
(1, 1), (1, 2), (2, 1), (1, .none), (.none, 1), (.none, .none)
|
|
]
|
|
|
|
return relationships.map { p($0, $1) }
|
|
}
|
|
|
|
OptionalTests.test("Equatable") {
|
|
expectEqual([true, false, false, false, false, true], testRelation(==))
|
|
expectEqual([false, true, true, true, true, false], testRelation(!=))
|
|
expectEqual([false, true, false, false, true, false], testRelation(<))
|
|
}
|
|
|
|
struct X {}
|
|
class C {}
|
|
|
|
class E : Equatable {}
|
|
func == (_: E, _: E) -> Bool { return true }
|
|
|
|
OptionalTests.test("initializers") {
|
|
let _: X? = nil
|
|
let _: X? = X()
|
|
|
|
let _: C? = nil
|
|
let _: C? = C()
|
|
}
|
|
|
|
OptionalTests.test("nil comparison") {
|
|
let v0: Int? = nil
|
|
let v1: Int? = 1
|
|
|
|
expectFalse(v1 == nil)
|
|
expectTrue(v1 != nil)
|
|
expectTrue(v0 == nil)
|
|
expectFalse(v0 != nil)
|
|
|
|
expectFalse(nil == v1)
|
|
expectTrue(nil != v1)
|
|
expectTrue(nil == v0)
|
|
expectFalse(nil != v0)
|
|
|
|
let e0: E? = nil
|
|
let e1: E? = E()
|
|
|
|
expectFalse(e1 == nil)
|
|
expectTrue(e1 != nil)
|
|
expectTrue(e0 == nil)
|
|
expectFalse(e0 != nil)
|
|
|
|
expectFalse(nil == e1)
|
|
expectTrue(nil != e1)
|
|
expectTrue(nil == e0)
|
|
expectFalse(nil != e0)
|
|
|
|
/*
|
|
// FIXME: <rdar://problem/17489239> Optional<T>() == nil where T: !Equatable
|
|
let _: X? = nil
|
|
let _: X? = X()
|
|
|
|
expectFalse(x1 == nil)
|
|
expectTrue(x1 != nil)
|
|
expectTrue(x0 == nil)
|
|
expectFalse(x0 != nil)
|
|
|
|
expectFalse(nil == x1)
|
|
expectTrue(nil != x1)
|
|
expectTrue(nil == x0)
|
|
expectFalse(nil != x0)
|
|
*/
|
|
}
|
|
|
|
OptionalTests.test("??") {
|
|
var counter = 0
|
|
func nextCounter() -> Int { counter += 1; return counter-1 }
|
|
func nextCounter2() -> Int? { return nextCounter() }
|
|
|
|
let a: Int? = 123
|
|
let b: Int? = nil
|
|
let c: Int? = nil
|
|
let d: Int? = 456
|
|
let e: Int? = nil
|
|
let f: Int? = nil
|
|
|
|
expectEqual(123, a ?? nextCounter())
|
|
expectEqual(0, b ?? nextCounter())
|
|
expectEqual(1, c ?? nextCounter())
|
|
expectEqual(456, d ?? nextCounter())
|
|
expectEqual(456, e ?? d ?? nextCounter())
|
|
expectEqual(2, f ?? nextCounter())
|
|
|
|
expectEqual(Optional(456), c ?? d)
|
|
expectEqual(nil, c ?? e)
|
|
expectEqual(Optional(123), a ?? nextCounter2())
|
|
expectEqual(Optional(3), b ?? nextCounter2())
|
|
expectEqual(Optional(4), c ?? nextCounter2())
|
|
expectEqual(Optional(456), d ?? nextCounter2())
|
|
expectEqual(Optional(456), e ?? d ?? nextCounter2())
|
|
expectEqual(Optional(5), f ?? nextCounter2())
|
|
}
|
|
|
|
OptionalTests.test("flatMap") {
|
|
let half: Int32 -> Int16? =
|
|
{ if $0 % 2 == 0 { return Int16($0 / 2) } else { return .none } }
|
|
|
|
expectOptionalEqual(2 as Int16, half(4))
|
|
expectEmpty(half(3))
|
|
|
|
expectEmpty((.none as Int32?).flatMap(half))
|
|
expectOptionalEqual(2 as Int16, (4 as Int32?).flatMap(half))
|
|
expectEmpty((3 as Int32?).flatMap(half))
|
|
}
|
|
|
|
@inline(never)
|
|
func anyToAny<T, U>(a: T, _ : U.Type) -> U {
|
|
return a as! U
|
|
}
|
|
@inline(never)
|
|
func anyToAnyOrNil<T, U>(a: T, _ : U.Type) -> U? {
|
|
return a as? U
|
|
}
|
|
func canGenericCast<T, U>(a: T, _ ty : U.Type) -> Bool {
|
|
return anyToAnyOrNil(a, ty) != nil
|
|
}
|
|
|
|
OptionalTests.test("Casting Optional") {
|
|
let x = C()
|
|
let sx: C? = x
|
|
let nx: C? = nil
|
|
expectTrue(anyToAny(x, Optional<C>.self)! === x)
|
|
expectTrue(anyToAny(sx, C.self) === x)
|
|
expectTrue(anyToAny(sx, Optional<C>.self)! === x)
|
|
|
|
expectTrue(anyToAny(nx, Optional<C>.self) == nil)
|
|
expectTrue(anyToAnyOrNil(nx, C.self) == nil)
|
|
|
|
let i = Int.max
|
|
let si: Int? = Int.max
|
|
let ni: Int? = nil
|
|
expectEqual(anyToAny(i, Optional<Int>.self)!, Int.max)
|
|
expectEqual(anyToAny(si, Int.self), Int.max)
|
|
expectEqual(anyToAny(si, Optional<Int>.self)!, Int.max)
|
|
|
|
expectTrue(anyToAny(ni, Optional<Int>.self) == nil)
|
|
expectTrue(anyToAnyOrNil(ni, Int.self) == nil)
|
|
|
|
let ssx: C?? = sx
|
|
expectTrue(anyToAny(ssx, Optional<C>.self)! === x)
|
|
expectTrue(anyToAny(x, Optional<Optional<C>>.self)!! === x)
|
|
expectTrue(anyToAnyOrNil(ni, Int.self) == nil)
|
|
|
|
// Test for SR-459: Weakened optionals don't zero.
|
|
var deinitRan = false
|
|
do {
|
|
var t = DeinitTester { deinitRan = true }
|
|
_ = anyToAny(Optional(t), CustomDebugStringConvertible.self)
|
|
}
|
|
expectTrue(deinitRan)
|
|
}
|
|
|
|
OptionalTests.test("Casting Optional Traps") {
|
|
let nx: C? = nil
|
|
expectCrashLater()
|
|
anyToAny(nx, Int.self)
|
|
}
|
|
|
|
class TestNoString {}
|
|
class TestString : CustomStringConvertible, CustomDebugStringConvertible {
|
|
var description: String {
|
|
return "AString"
|
|
}
|
|
var debugDescription: String {
|
|
return "XString"
|
|
}
|
|
}
|
|
class TestStream : Streamable {
|
|
func write<Target : OutputStream>(to target: inout Target) {
|
|
target.write("AStream")
|
|
}
|
|
}
|
|
|
|
func debugPrintStr<T>(a: T) -> String {
|
|
var s = ""
|
|
debugPrint(a, terminator: "", to: &s)
|
|
return s
|
|
}
|
|
// Optional should not conform to output stream protocols itself, but is
|
|
// convertible to them if its wrapped type is.
|
|
// Furthermore, printing an Optional should always print the debug
|
|
// description regardless of whether the wrapper type conforms to an
|
|
// output stream protocol.
|
|
OptionalTests.test("Optional OutputStream") {
|
|
let optNoString: TestNoString? = TestNoString()
|
|
expectFalse(optNoString is CustomStringConvertible)
|
|
expectFalse(canGenericCast(optNoString, CustomStringConvertible.self))
|
|
expectFalse(optNoString is Streamable)
|
|
expectFalse(canGenericCast(optNoString, Streamable.self))
|
|
expectTrue(optNoString is CustomDebugStringConvertible)
|
|
expectTrue(canGenericCast(optNoString, CustomDebugStringConvertible.self))
|
|
expectEqual(String(optNoString), "Optional(main.TestNoString)")
|
|
expectEqual(debugPrintStr(optNoString), "Optional(main.TestNoString)")
|
|
|
|
let iouNoString: TestNoString! = TestNoString()
|
|
// IUO directly conforms to CustomStringConvertible.
|
|
// Disabled pending SR-164
|
|
// expectTrue(iouNoString is CustomStringConvertible)
|
|
expectTrue(canGenericCast(iouNoString, CustomStringConvertible.self))
|
|
expectFalse(iouNoString is Streamable)
|
|
expectFalse(canGenericCast(iouNoString, Streamable.self))
|
|
// CustomDebugStringConvertible conformance is a temporary hack.
|
|
// Disabled pending SR-164
|
|
// expectTrue(iouNoString is CustomDebugStringConvertible)
|
|
expectTrue(canGenericCast(iouNoString, CustomDebugStringConvertible.self))
|
|
expectEqual(String(iouNoString), "main.TestNoString")
|
|
expectEqual(debugPrintStr(iouNoString), "main.TestNoString")
|
|
|
|
let optString: TestString? = TestString()
|
|
expectTrue(optString is CustomStringConvertible)
|
|
expectTrue(canGenericCast(optString, CustomStringConvertible.self))
|
|
expectTrue(optString is CustomDebugStringConvertible)
|
|
expectTrue(canGenericCast(optString, CustomDebugStringConvertible.self))
|
|
expectEqual(String(TestString()), "AString")
|
|
expectEqual(String(optString), "Optional(XString)")
|
|
expectEqual(debugPrintStr(optString), "Optional(XString)")
|
|
|
|
let iouString: TestString! = TestString()
|
|
expectTrue(iouString is CustomStringConvertible)
|
|
expectTrue(canGenericCast(iouString, CustomStringConvertible.self))
|
|
// CustomDebugStringConvertible conformance is a temporary hack.
|
|
expectTrue(iouString is CustomDebugStringConvertible)
|
|
expectTrue(canGenericCast(iouString, CustomDebugStringConvertible.self))
|
|
expectEqual(String(iouString), "AString")
|
|
// FIXME: Ideally the debug output would be "XString", but a reasonable
|
|
// implementation of that behavior requires conditional conformance.
|
|
// (directly invoking debugPrint(Any) already works correctly).
|
|
expectEqual(debugPrintStr(iouString), "AString")
|
|
|
|
let optStream: TestStream? = TestStream()
|
|
expectTrue(optStream is Streamable)
|
|
expectTrue(canGenericCast(optStream, Streamable.self))
|
|
expectTrue(optStream is CustomDebugStringConvertible)
|
|
expectTrue(canGenericCast(optStream, CustomDebugStringConvertible.self))
|
|
expectEqual(String(TestStream()), "AStream")
|
|
expectEqual(String(optStream), "Optional(AStream)")
|
|
expectEqual(debugPrintStr(optStream), "Optional(AStream)")
|
|
}
|
|
|
|
OptionalTests.test("unsafelyUnwrapped") {
|
|
let empty: Int? = nil
|
|
let nonEmpty: Int? = 3
|
|
expectEqual(3, nonEmpty.unsafelyUnwrapped)
|
|
expectCrashLater()
|
|
empty.unsafelyUnwrapped
|
|
}
|
|
|
|
runAllTests()
|