// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: reflection
// XFAIL: swift_test_mode_optimize_none_with_opaque_values

import StdlibUnittest
import Swift


let OptionalTests = TestSuite("Optional")
defer { runAllTests() }

protocol TestProtocol1 {}

// Check the generic parameter name.
extension Optional 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)

  do {
    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!.advanced(by: 1))."
  )
}

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(!=))
}

OptionalTests.test("Hashable") {
    let o1: Optional<Int> = .some(1010)
    let o2: Optional<Int> = .some(2020)
    let o3: Optional<Int> = .none
    checkHashable([o1, o2, o3], equalityOracle: { $0 == $1 })

    let oo1: Optional<Optional<Int>> = .some(.some(1010))
    let oo2: Optional<Optional<Int>> = .some(.some(2010))
    let oo3: Optional<Optional<Int>> = .some(.none)
    let oo4: Optional<Optional<Int>> = .none
    checkHashable([oo1, oo2, oo3, oo4], equalityOracle: { $0 == $1 })
}

OptionalTests.test("CustomReflectable") {
  // Test with a non-refcountable type.
  do {
    let value: OpaqueValue<Int>? = nil
    var output = ""
    dump(value, to: &output)
    expectEqual("- nil\n", output)
    expectEqual(.optional, Mirror(reflecting: value).displayStyle)
  }
  do {
    let value: OpaqueValue<Int>? = OpaqueValue(1010)
    var output = ""
    dump(value, to: &output)
    let expected =
      "▿ Optional(StdlibUnittest.OpaqueValue<Swift.Int>(value: 1010, identity: 0))\n" +
      "  ▿ some: StdlibUnittest.OpaqueValue<Swift.Int>\n" +
      "    - value: 1010\n" +
      "    - identity: 0\n"
    expectEqual(expected, output)
    expectEqual(.optional, Mirror(reflecting: value).displayStyle)
  }
  // Test with a reference type.
  do {
    let value: LifetimeTracked? = nil
    var output = ""
    dump(value, to: &output)
    expectEqual("- nil\n", output)
    expectEqual(.optional, Mirror(reflecting: value).displayStyle)
  }
  do {
    let value: LifetimeTracked? = LifetimeTracked(1010)
    var output = ""
    dump(value, to: &output)
    let expected =
      "▿ Optional(1010)\n" +
      "  ▿ some: 1010 #0\n" +
      "    - value: 1010\n" +
      "    - identity: 0\n" +
      "    - serialNumber: 1\n"
    expectEqual(expected, output)
    expectEqual(.optional, Mirror(reflecting: value).displayStyle)
  }
}

struct X {}
class C {}
class D {}

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 } }

  expectEqual(2 as Int16, half(4))
  expectNil(half(3))

  expectNil((.none as Int32?).flatMap(half))
  expectEqual(2 as Int16, (4 as Int32?).flatMap(half))
  expectNil((3 as Int32?).flatMap(half))
}

// FIXME: @inline(never) does not inhibit specialization

@inline(never)
@_optimize(none)
func anyToAny<T, U>(_ a: T, _ : U.Type) -> U {
  return a as! U
}

@inline(never)
@_optimize(none)
func anyToAnyIs<T, U>(_ a: T, _ : U.Type) -> Bool {
  return a is U
}

@inline(never)
@_optimize(none)
func anyToAnyIsOptional<T, U>(_ a: T?, _ : U.Type) -> Bool {
  return a is U?
}

@inline(never)
@_optimize(none)
func anyToAnyOrNil<T, U>(_ a: T, _ : U.Type) -> U? {
  return a as? U
}

@inline(never)
@_optimize(none)
func canGenericCast<T, U>(_ a: T, _ ty : U.Type) -> Bool {
  return anyToAnyOrNil(a, ty) != nil
}

protocol TestExistential {}
extension Int : TestExistential {}

OptionalTests.test("Casting Optional") {
  let x = C()
  let sx: C? = x
  let nx: C? = nil
  expectTrue(anyToAny(x, Optional<C>.self)! === x)
  expectTrue(anyToAnyIs(x, Optional<C>.self))
  expectFalse(anyToAnyIs(x, Optional<D>.self))

  expectTrue(anyToAny(sx, C.self) === x)
  expectTrue(anyToAnyIs(sx, C.self))
  expectFalse(anyToAnyIs(sx, D.self))

  expectTrue(anyToAny(sx, Optional<C>.self)! === x)
  expectTrue(anyToAnyIs(sx, Optional<C>.self))
  expectTrue(anyToAnyIsOptional(sx, C.self))
  expectFalse(anyToAnyIsOptional(sx, D.self))

  expectTrue(anyToAny(nx, Optional<C>.self) == nil)
  expectTrue(anyToAnyIs(nx, Optional<C>.self))

  // You can cast a nil of any type to a nil of any other type
  // successfully
  expectTrue(anyToAnyIs(nx, Optional<D>.self))

  expectTrue(anyToAnyIsOptional(nx, C.self))

  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)

  // https://github.com/apple/swift/issues/43076
  // Weakened optionals don't zero
  var t = LifetimeTracked(0)
  _ = anyToAny(Optional(t), CustomDebugStringConvertible.self)
  expectTrue(anyToAnyIs(Optional(t), CustomDebugStringConvertible.self))

  // https://github.com/apple/swift/issues/43524
  // Runtime exception casting an 'Any' nil to an 'Optional'
  let oi: Int? = nil
  expectTrue(anyToAny(oi as Any, Optional<Int>.self) == nil)
  expectTrue(anyToAnyIs(oi as Any, Optional<Int>.self))

  // Double-wrapped optional
  expectTrue(anyToAnyIsOptional(oi as Any, Int.self))

  // For good measure test an existential that Optional does not conform to.
  expectTrue(anyToAny(3 as TestExistential, Optional<Int>.self) == 3)

  // Can't do existential + optional wrapping at once for some reason
  expectTrue(anyToAnyIs(3 as TestExistential, Optional<Int>.self))
  expectTrue(anyToAnyIsOptional(3 as TestExistential, Int.self))

  // And a type that is not convertible to its target.
  expectTrue(anyToAny(nx as Any, Optional<Int>.self) == nil)
  expectTrue(anyToAnyIs(nx as Any, Optional<Int>.self))
  expectTrue(anyToAnyIsOptional(nx as Any, Int.self))

  expectTrue(anyToAnyOrNil(sx as Any, Optional<Int>.self) == nil)
  expectFalse(anyToAnyIs(sx as Any, Optional<Int>.self))
  expectFalse(anyToAnyIsOptional(sx as Any, Int.self))

  // OK to convert nil of any type to optional of any other type
  expectTrue(anyToAnyIs(Optional<(String, String)>.none, Optional<Bool>.self))
  expectTrue(anyToAnyIsOptional(Optional<(String, String)>.none, Bool.self))
}

OptionalTests.test("Casting Optional Traps")
.require(.crashTesting)
.code {
  let nx: C? = nil
  expectCrash { _blackHole(anyToAny(nx, Int.self)) }
}
OptionalTests.test("Casting Optional Any Traps")
.require(.crashTesting)
.code {
  let nx: X? = X()
  expectCrash { _blackHole(anyToAny(nx as Any, Optional<Int>.self)) }
}

class TestNoString {}
class TestString : CustomStringConvertible, CustomDebugStringConvertible {
  var description: String {
    return "AString"
  }
  var debugDescription: String {
    return "XString"
  }
}
class TestStream : TextOutputStreamable {
  func write<Target : TextOutputStream>(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 TextOutputStream") {
  let optNoString: TestNoString? = TestNoString()
  expectFalse(optNoString is CustomStringConvertible)
  expectFalse(canGenericCast(optNoString, CustomStringConvertible.self))
  expectFalse(optNoString is TextOutputStreamable)
  expectFalse(canGenericCast(optNoString, TextOutputStreamable.self))
  expectTrue(optNoString is CustomDebugStringConvertible)
  expectTrue(canGenericCast(optNoString, CustomDebugStringConvertible.self))
  expectEqual(String(describing: optNoString), "Optional(main.TestNoString)")
  expectEqual(debugPrintStr(optNoString), "Optional(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(describing: TestString()), "AString")
  expectEqual(String(describing: optString), "Optional(XString)")
  expectEqual(debugPrintStr(optString), "Optional(XString)")

  let optStream: TestStream? = TestStream()
  expectTrue(optStream is TextOutputStreamable)
  expectTrue(canGenericCast(optStream, TextOutputStreamable.self))
  expectTrue(optStream is CustomDebugStringConvertible)
  expectTrue(canGenericCast(optStream, CustomDebugStringConvertible.self))
  expectEqual(String(describing: TestStream()), "AStream")
  expectEqual(String(describing: optStream), "Optional(AStream)")
  expectEqual(debugPrintStr(optStream), "Optional(AStream)")
}

OptionalTests.test("unsafelyUnwrapped") {
  let nonEmpty: Int? = 3
  expectEqual(3, nonEmpty.unsafelyUnwrapped)
}

OptionalTests.test("unsafelyUnwrapped nil")
  .require(.crashTesting)
  .xfail(.custom(
    { !_isDebugAssertConfiguration() },
    reason: "assertions are disabled in Release and Unchecked mode"))
  .code {
  let empty: Int? = nil
  expectCrashLater()
  _blackHole(empty.unsafelyUnwrapped)
}

OptionalTests.test("_span() from Optional.none")
.require(.stdlib_6_2).code {
  var o = Optional<[Int]>.none
  let span = o._span()
  // o = [1, 2, 3] // Does not compile, exclusivity violation
  expectEqual(span.count, 0)

  // make it fail at test time if exclusivity was violated
  expectNil(o, "fail due to exclusivity violation")
}

OptionalTests.test("_span() from Optional.some")
.require(.stdlib_6_2).code {
  let a: [Int] = [1, 2, 3]
  var o: Optional = a
  let span = o._span()
  // o = nil // Does not compile, exclusivity violation
  expectEqual(span.count, 1)
  expectEqual(span[0], o, "accessed mysterious memory location")

  expectNotNil(o, "fail due to exclusivity violation")

  let b = [4, 5, 6]
  // o = b // Does not compile, exclusivity violation
  expectNotEqual(span[0], b, "accessed mysterious memory location")
}
