//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2026 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
//
//===----------------------------------------------------------------------===//


import SwiftPrivate
import SwiftPrivateThreadExtras
import SwiftPrivateLibcExtras

#if canImport(Darwin)
#if _runtime(_ObjC)
internal import Foundation
#endif
internal import Darwin
internal import var Darwin.errno
#elseif canImport(Glibc)
internal import Glibc
#elseif canImport(Musl)
internal import Musl
#elseif canImport(Android)
internal import Android
#elseif os(WASI)
internal import WASILibc
#elseif os(Emscripten)
internal import EmscriptenLibc
#elseif os(Windows)
internal import CRT
internal import WinSDK
#endif

#if _runtime(_ObjC)
internal import ObjectiveC
#endif

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
import _Concurrency
#endif

#if os(WASI) || os(Emscripten)
let platformSupportsChildProcesses = false
#else
let platformSupportsChildProcesses = true
#endif

extension String {
  /// Returns the lines in `self`.
  public var _lines : [String] {
    return _split(separator: "\n")
  }

  /// Splits `self` at occurrences of `separator`.
  public func _split(separator: Unicode.Scalar) -> [String] {
    let scalarSlices = unicodeScalars.split { $0 == separator }
    return scalarSlices.map { String(String.UnicodeScalarView($0)) }
  }
}

public struct SourceLoc {
  public let file: String
  public let line: UInt
  public let comment: String?

  public init(_ file: String, _ line: UInt, comment: String? = nil) {
    self.file = file
    self.line = line
    self.comment = comment
  }

  public func withCurrentLoc(
    _ file: String = #file, line: UInt = #line
  ) -> SourceLocStack {
    return SourceLocStack(self).with(SourceLoc(file, line))
  }
}

public struct SourceLocStack {
  let locs: [SourceLoc]

  public init() {
    locs = []
  }

  public init(_ loc: SourceLoc) {
    locs = [loc]
  }

  init(_locs: [SourceLoc]) {
    locs = _locs
  }

  var isEmpty: Bool {
    return locs.isEmpty
  }

  public func with(_ loc: SourceLoc) -> SourceLocStack {
    var locs = self.locs
    locs.append(loc)
    return SourceLocStack(_locs: locs)
  }

  public func pushIf(
    _ showFrame: Bool, file: String, line: UInt
  ) -> SourceLocStack {
    return showFrame ? self.with(SourceLoc(file, line)) : self
  }

  public func withCurrentLoc(
    file: String = #file, line: UInt = #line
  ) -> SourceLocStack {
    return with(SourceLoc(file, line))
  }

  public func print() {
    let top = locs.first!
    Swift.print("check failed at \(top.file), line \(top.line)")
    _printStackTrace(SourceLocStack(_locs: Array(locs.dropFirst())))
  }
}

fileprivate struct AtomicBool {
    
    private var _value: _stdlib_AtomicInt
    
    init(_ b: Bool) { self._value = _stdlib_AtomicInt(b ? 1 : 0) }
    
    func store(_ b: Bool) { _value.store(b ? 1 : 0) }
    
    func load() -> Bool { return _value.load() != 0 }
    
    @discardableResult
    func orAndFetch(_ b: Bool) -> Bool {
        return _value.orAndFetch(b ? 1 : 0) != 0
    }

    func fetchAndClear() -> Bool {
        return _value.fetchAndAnd(0) != 0
    }
}

func _printStackTrace(_ stackTrace: SourceLocStack?) {
  guard let s = stackTrace, !s.locs.isEmpty else { return }
  print("stacktrace:")
  for (i, loc) in s.locs.reversed().enumerated() {
    let comment = (loc.comment != nil) ? " ; \(loc.comment!)" : ""
    print("  #\(i): \(loc.file):\(loc.line)\(comment)")
  }
}

fileprivate var _anyExpectFailed = AtomicBool(false)
fileprivate var _seenExpectCrash = AtomicBool(false)

/// Run `body` and expect a failure to happen.
///
/// The check passes iff `body` triggers one or more failures.
public func expectFailure(
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line, invoking body: () -> Void) {
  let startAnyExpectFailed = _anyExpectFailed.fetchAndClear()
  body()
  let endAnyExpectFailed = _anyExpectFailed.fetchAndClear()
  expectTrue(
    endAnyExpectFailed, "running `body` should produce an expected failure",
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
  )
  _anyExpectFailed.orAndFetch(startAnyExpectFailed)
}

/// An opaque function that ignores its argument and returns nothing.
public func noop<T>(_ value: T) {}

/// An opaque function that simply returns its argument.
public func identity<T>(_ value: T) -> T {
  return value
}

public func identity(_ element: OpaqueValue<Int>) -> OpaqueValue<Int> {
  return element
}

public func identityEq(_ element: MinimalEquatableValue) -> MinimalEquatableValue {
  return element
}

public func identityComp(_ element: MinimalComparableValue)
  -> MinimalComparableValue {
  return element
}

public func expectEqual<T : Equatable>(
  _ first: T,
  _ second: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqualTest(first, second, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
}

public func expectEqual<T : Equatable, U : Equatable>(
  _ first: (T, U),
  _ second: (T, U),
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqualTest(first.0, second.0, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
  expectEqualTest(first.1, second.1, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
}

public func expectEqual<T : Equatable, U : Equatable, V : Equatable>(
  _ first: (T, U, V),
  _ second: (T, U, V),
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqualTest(first.0, second.0, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
  expectEqualTest(first.1, second.1, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
  expectEqualTest(first.2, second.2, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
}

public func expectEqual<T : Equatable, U : Equatable, V : Equatable, W : Equatable>(
  _ first: (T, U, V, W),
  _ second: (T, U, V, W),
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqualTest(first.0, second.0, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
  expectEqualTest(first.1, second.1, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
  expectEqualTest(first.2, second.2, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
  expectEqualTest(first.3, second.3, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 == $1}
}

public func expectEqual(
  _ first: String,
  _ second: Substring,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !(first == second) {
    expectationFailure(
      """
      first:  \(String(reflecting: first)) (of type \(String(reflecting: type(of: first))))
      second: \(String(reflecting: second)) (of type \(String(reflecting: type(of: second))))
      """,
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
    )
  }
}
public func expectEqual(
  _ first: Substring,
  _ second: String,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !(first == second) {
    expectationFailure(
      """
      first:  \(String(reflecting: first)) (of type \(String(reflecting: type(of: first))))
      second: \(String(reflecting: second)) (of type \(String(reflecting: type(of: second))))
      """,
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
    )
  }
}
public func expectEqual(
  _ first: String,
  _ second: String,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !(first == second) {
    expectationFailure(
      """
      first:  \(String(reflecting: first)) (of type \(String(reflecting: type(of: first))))
      second: \(String(reflecting: second)) (of type \(String(reflecting: type(of: second))))
      """,
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
    )
  }
}

public func expectEqualReference(
  _ first: AnyObject?,
  _ second: AnyObject?,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqualTest(first, second, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false) {$0 === $1}
}

public func expectationFailure(
  _ reason: String,
  trace message: String,
  stackTrace: SourceLocStack) {
  _anyExpectFailed.store(true)
  stackTrace.print()
  print(reason, terminator: reason == "" ? "" : "\n")
  print(message, terminator: message == "" ? "" : "\n")
}

// Renamed to avoid collision with expectEqual(_, _, TRACE).
// See <rdar://26058520> Generic type constraints incorrectly applied to
// functions with the same name
public func expectEqualTest<T>(
  _ first: T,
  _ second: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line,
  sameValue equal: (T, T) -> Bool
) {
  if !equal(first, second) {
    expectationFailure(
      """
      first:  \(String(reflecting: first)) (of type \(String(reflecting: type(of: first))))
      second: \(String(reflecting: second)) (of type \(String(reflecting: type(of: second))))
      """,
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
    )
  }
}

public func expectNotEqual<T : Equatable>(
  _ first: T,
  _ second: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if first == second {
    expectationFailure(
      "unexpected value: \"\(second)\" (of type \(String(reflecting: type(of: second))))",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
    )
  }
}

public func expectOptionalEqual<T>(
  _ first: T,
  _ second: T?,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line,
  sameValue equal: (T, T) -> Bool
) {
  if (second == nil) || !equal(first, second!) {
    expectationFailure(
      """
      first:  \"\(first)\" (of type \(String(reflecting: type(of: first))))
      second: \"\(second.debugDescription)\" (of type \(String(reflecting: type(of: second))))
      """,
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectEqual(
  _ first: Any.Type, _ second: Any.Type,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  expectEqualTest(
    first, second, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), showFrame: false
  ) { $0 == $1 }
}

public func expectLT<T : Comparable>(_ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if !(lhs < rhs) {
    expectationFailure("\(lhs) < \(rhs)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  } else if !(rhs > lhs) {
    expectationFailure("\(lhs) < \(rhs) (flipped)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectLE<T : Comparable>(_ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if !(lhs <= rhs) {
    expectationFailure("\(lhs) <= \(rhs)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  } else if !(rhs >= lhs) {
    expectationFailure("\(lhs) <= \(rhs) (flipped)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectGT<T : Comparable>(_ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if !(lhs > rhs) {
    expectationFailure("\(lhs) > \(rhs)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  } else if !(rhs < lhs) {
    expectationFailure("\(lhs) > \(rhs) (flipped)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectGE<T : Comparable>(_ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if !(lhs >= rhs) {
    expectationFailure("\(lhs) >= \(rhs)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  } else if !(rhs <= lhs) {
    expectationFailure("\(lhs) >= \(rhs) (flipped)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

extension Range {
  internal func _contains(_ other: Range<Bound>) -> Bool {
    if other.lowerBound < lowerBound { return false }
    if upperBound < other.upperBound { return false }
    return true
  }
}
extension Range {
  internal func _contains(_ other: ClosedRange<Bound>) -> Bool {
    if other.lowerBound < lowerBound { return false }
    if upperBound <= other.upperBound { return false }
    return true
  }
}

public func expectTrapping<Bound>(
  _ point: Bound, in range: Range<Bound>,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !range.contains(point) {
    expectationFailure("\(point) in \(range)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    _trappingExpectationFailedCallback()
  }
}

public func expectTrapping<Bound>(
  _ subRange: Range<Bound>, in range: Range<Bound>,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !range._contains(subRange) {
    expectationFailure("\(subRange) in \(range)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    _trappingExpectationFailedCallback()
  }
}
public func expectTrapping<Bound>(
  _ point: Bound, in range: ClosedRange<Bound>,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !range.contains(point) {
    expectationFailure("\(point) in \(range)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    _trappingExpectationFailedCallback()
  }
}

public func expectTrapping<Bound>(
  _ subRange: ClosedRange<Bound>, in range: Range<Bound>,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !range._contains(subRange) {
    expectationFailure("\(subRange) in \(range)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    _trappingExpectationFailedCallback()
  }
}

extension ClosedRange {
  internal func _contains(_ other: ClosedRange<Bound>) -> Bool {
    if other.lowerBound < lowerBound { return false }
    if upperBound < other.upperBound { return false }
    return true
  }
}

public func expectTrapping<Bound>(
  _ subRange: ClosedRange<Bound>, in range: ClosedRange<Bound>,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if !range._contains(subRange) {
    expectationFailure("\(subRange) in \(range)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    _trappingExpectationFailedCallback()
  }
}

public func expectType<T>(_: T.Type, _ x: inout T) {}
public func expectEqualType<T>(_: T.Type, _: T.Type) {}

public func expectSequenceType<X : Sequence>(_ x: X) -> X {
  return x
}

public func expectCollectionType<X : Collection>(
  _ x: X.Type
) {}
public func expectMutableCollectionType<X : MutableCollection>(
  _ x: X.Type
) {}

/// A slice is a `Collection` that when sliced returns an instance of
/// itself.
public func expectSliceType<X : Collection>(
  _ sliceType: X.Type
) where X.SubSequence == X {}

/// A mutable slice is a `MutableCollection` that when sliced returns an
/// instance of itself.
public func expectMutableSliceType<X : MutableCollection>(
  _ mutableSliceType: X.Type
) where X.SubSequence == X {}

/// Check that all associated types of a `Sequence` are what we expect them
/// to be.
public func expectSequenceAssociatedTypes<X : Sequence>(
  sequenceType: X.Type,
  iteratorType: X.Iterator.Type
) {}

/// Check that all associated types of a `Collection` are what we expect them
/// to be.
public func expectCollectionAssociatedTypes<X : Collection>(
  collectionType: X.Type,
  iteratorType: X.Iterator.Type,
  subSequenceType: X.SubSequence.Type,
  indexType: X.Index.Type,
  indicesType: X.Indices.Type
) {}

/// Check that all associated types of a `BidirectionalCollection` are what we
/// expect them to be.
public func expectBidirectionalCollectionAssociatedTypes<X : BidirectionalCollection>(
  collectionType: X.Type,
  iteratorType: X.Iterator.Type,
  subSequenceType: X.SubSequence.Type,
  indexType: X.Index.Type,
  indicesType: X.Indices.Type
) {}

/// Check that all associated types of a `RandomAccessCollection` are what we
/// expect them to be.
public func expectRandomAccessCollectionAssociatedTypes<X : RandomAccessCollection>(
  collectionType: X.Type,
  iteratorType: X.Iterator.Type,
  subSequenceType: X.SubSequence.Type,
  indexType: X.Index.Type,
  indicesType: X.Indices.Type
) {}

public struct AssertionResult : CustomStringConvertible {
  init(isPass: Bool) {
    self._isPass = isPass
  }

  public func withDescription(_ description: String) -> AssertionResult {
    var result = self
    result.description += description
    return result
  }

  let _isPass: Bool

  public var description: String = ""
}

public func assertionSuccess() -> AssertionResult {
  return AssertionResult(isPass: true)
}

public func assertionFailure() -> AssertionResult {
  return AssertionResult(isPass: false)
}

public func expectUnreachable(
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  expectationFailure("this code should not be executed", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}

public func expectUnreachableCatch(_ error: Error,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  expectationFailure(
    "error should not be thrown: \"\(error)\"", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}

public func expectTrue(_ actual: AssertionResult,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if !actual._isPass {
    expectationFailure(
      "expected: passed assertion\n\(actual.description)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectFalse(_ actual: AssertionResult,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if actual._isPass {
    expectationFailure(
      "expected: failed assertion\n\(actual.description)", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectTrue(_ actual: Bool,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if !actual {
    expectationFailure("expected: true", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectFalse(_ actual: Bool,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  if actual {
    expectationFailure("expected: false", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectThrows<ErrorType: Error & Equatable>(
  _ expectedError: ErrorType? = nil, _ test: () throws -> Void,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  do {
    try test()
  } catch let error as ErrorType {
    if let expectedError = expectedError {
      expectEqual(expectedError, error)
    }
  } catch {
    expectationFailure("unexpected error thrown: \"\(error)\"", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectDoesNotThrow(_ test: () throws -> Void,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  do {
    try test()
  } catch {
    expectationFailure("unexpected error thrown: \"\(error)\"", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectNil<T>(
  _ value: T?,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if value != nil {
    expectationFailure(
      "expected optional to be nil\nactual: \"\(value!)\"",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectNil<T: ~Copyable & ~Escapable>(
  _ value: borrowing T?,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  if value != nil {
    expectationFailure(
      "expected optional to be nil",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)
    )
  }
}

@discardableResult
@_lifetime(copy value)
public func expectNotNil<T: ~Copyable & ~Escapable>(
  _ value: consuming T?,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) -> T? {
  if value == nil {
    expectationFailure("expected optional to be non-nil", trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
  return value
}

public func expectCrashLater(withMessage message: String = "") {
  print("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed.load())")

  var stderr = _Stderr()
  print("\(_stdlibUnittestStreamPrefix);expectCrash;\(message)", to: &stderr)

  _seenExpectCrash.store(true)
}

public func expectCrash(withMessage message: String = "", executing: () -> Void) -> Never {
  expectCrashLater(withMessage: message)
  executing()
  expectUnreachable()
  fatalError()
}

func _defaultTestSuiteFailedCallback() {
  fflush(nil)
  abort()
}

var _testSuiteFailedCallback: () -> Void = _defaultTestSuiteFailedCallback

public func _setTestSuiteFailedCallback(_ callback: @escaping () -> Void) {
  _testSuiteFailedCallback = callback
}

func _defaultTrappingExpectationFailedCallback() {
  fflush(nil)
  abort()
}

var _trappingExpectationFailedCallback: () -> Void
  = _defaultTrappingExpectationFailedCallback

public func _setTrappingExpectationFailedCallback(callback: @escaping () -> Void) {
  _trappingExpectationFailedCallback = callback
}

extension ProcessTerminationStatus {
  var isSwiftTrap: Bool {
    switch self {
    case .signal(let signal):
#if os(Windows)
      return CInt(signal) == SIGILL
#elseif os(WASI)
      // No signals support on WASI yet, see https://github.com/WebAssembly/WASI/issues/166.
      return false
#else
      return CInt(signal) == SIGILL || CInt(signal) == SIGTRAP
#endif
    default:
      // This default case is needed for standard library builds where
      // resilience is enabled.
      // FIXME: Add the .exit case when there is a way to suppress when not.
      //   case .exit: return false
      return false
    }
  }
}

func _stdlib_getline() -> String? {
  var result: [UInt8] = []
  while true {
    let c = getchar()
    if c == EOF {
      if result.isEmpty {
        return nil
      }
      return String(decoding: result, as: UTF8.self)
    }
    if c == CInt(Unicode.Scalar("\n").value) {
      return String(decoding: result, as: UTF8.self)
    }
    result.append(UInt8(c))
  }
}

func _printDebuggingAdvice(_ fullTestName: String) {
  print("To debug, run:")
  var invocation = [CommandLine.arguments[0]]
#if os(Windows)
  var buffer: UnsafeMutablePointer<CChar>?
  var length: Int = 0
  if _dupenv_s(&buffer, &length, "SWIFT_INTERPRETER") != 0, let buffer = buffer {
    invocation.insert(String(cString: buffer), at: 0)
    free(buffer)
  }
#else
  let interpreter = getenv("SWIFT_INTERPRETER")
  if interpreter != nil {
    if let interpreterCmd = String(validatingCString: interpreter!) {
        invocation.insert(interpreterCmd, at: 0)
    }
  }
#endif
  print("$ \(invocation.joined(separator: " ")) " +
    "--stdlib-unittest-in-process --stdlib-unittest-filter \"\(fullTestName)\"")
}

var _allTestSuites: [TestSuite] = []
var _testSuiteNameToIndex: [String : Int] = [:]

let _stdlibUnittestStreamPrefix = "__STDLIB_UNITTEST__"
let _crashedPrefix = "CRASHED:"

@_silgen_name("installTrapInterceptor")
func _installTrapInterceptor()

#if _runtime(_ObjC)
@objc protocol _StdlibUnittestNSException {
  @objc optional var name: AnyObject { get }
}
#endif

// Avoid serializing references to objc_setUncaughtExceptionHandler in SIL.
@inline(never)
func _childProcess() {
  _installTrapInterceptor()

#if _runtime(_ObjC)
  objc_setUncaughtExceptionHandler {
    let exception = ($0 as Optional)! as AnyObject
    var stderr = _Stderr()
    let maybeNSException =
        unsafeBitCast(exception, to: _StdlibUnittestNSException.self)
    if let name = maybeNSException.name {
      print("*** [StdlibUnittest] Terminating due to uncaught exception " +
        "\(name): \(exception)",
        to: &stderr)
    } else {
      print("*** [StdlibUnittest] Terminating due to uncaught exception: " +
        "\(exception)",
        to: &stderr)
    }
  }
#endif

  while let line = _stdlib_getline() {
    let parts = line._split(separator: ";")

    if parts[0] == _stdlibUnittestStreamPrefix {
      precondition(parts[1] == "shutdown")
      return
    }

    let testSuiteName = parts[0]
    let testName = parts[1]
    var testParameter: Int?
    if parts.count > 2 {
      testParameter = Int(parts[2])!
    } else {
      testParameter = nil
    }

    let testSuite = _allTestSuites[_testSuiteNameToIndex[testSuiteName]!]
    _anyExpectFailed.store(false)
    testSuite._runTest(name: testName, parameter: testParameter)

    print("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed.load())")

    var stderr = _Stderr()
    print("\(_stdlibUnittestStreamPrefix);end", to: &stderr)

    if testSuite._shouldShutDownChildProcess(forTestNamed: testName) {
      return
    }
  }
}

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
@available(SwiftStdlib 5.1, *)
@inline(never)
func _childProcessAsync() async {
  _installTrapInterceptor()

#if _runtime(_ObjC)
  objc_setUncaughtExceptionHandler {
    let exception = ($0 as Optional)! as AnyObject
    var stderr = _Stderr()
    let maybeNSException =
        unsafeBitCast(exception, to: _StdlibUnittestNSException.self)
    if let name = maybeNSException.name {
      print("*** [StdlibUnittest] Terminating due to uncaught exception " +
        "\(name): \(exception)",
        to: &stderr)
    } else {
      print("*** [StdlibUnittest] Terminating due to uncaught exception: " +
        "\(exception)",
        to: &stderr)
    }
  }
#endif

  while let line = _stdlib_getline() {
    let parts = line._split(separator: ";")

    if parts[0] == _stdlibUnittestStreamPrefix {
      precondition(parts[1] == "shutdown")
      return
    }

    let testSuiteName = parts[0]
    let testName = parts[1]
    var testParameter: Int?
    if parts.count > 2 {
      testParameter = Int(parts[2])!
    } else {
      testParameter = nil
    }

    let testSuite = _allTestSuites[_testSuiteNameToIndex[testSuiteName]!]
    _anyExpectFailed.store(false)
    await testSuite._runTestAsync(name: testName, parameter: testParameter)

    print("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed.load())")

    var stderr = _Stderr()
    print("\(_stdlibUnittestStreamPrefix);end", to: &stderr)

    if testSuite._shouldShutDownChildProcess(forTestNamed: testName) {
      return
    }
  }
}
#endif

class _ParentProcess {
#if os(Windows)
  internal var _process: HANDLE = INVALID_HANDLE_VALUE
  internal var _childStdin: _FDOutputStream =
      _FDOutputStream(handle: INVALID_HANDLE_VALUE)
  internal var _childStdout: _FDInputStream =
      _FDInputStream(handle: INVALID_HANDLE_VALUE)
  internal var _childStderr: _FDInputStream =
      _FDInputStream(handle: INVALID_HANDLE_VALUE)
#else
  internal var _pid: pid_t?
  internal var _childStdin: _FDOutputStream = _FDOutputStream(fd: -1)
  internal var _childStdout: _FDInputStream = _FDInputStream(fd: -1)
  internal var _childStderr: _FDInputStream = _FDInputStream(fd: -1)
#endif

  internal var _runTestsInProcess: Bool
  internal var _filter: String?
  internal var _args: [String]

  init(runTestsInProcess: Bool, args: [String], filter: String?) {
    self._runTestsInProcess = runTestsInProcess
    self._filter = filter
    self._args = args
  }

  func _spawnChild() {
    let params = ["--stdlib-unittest-run-child"] + _args
#if os(Windows)
    let (hProcess, hStdIn, hStdOut, hStdErr) = spawnChild(params)
    self._process = hProcess
    self._childStdin = _FDOutputStream(handle: hStdIn)
    self._childStdout = _FDInputStream(handle: hStdOut)
    self._childStderr = _FDInputStream(handle: hStdErr)
#else
    let (pid, childStdinFD, childStdoutFD, childStderrFD) = spawnChild(params)
    _pid = pid
    _childStdin = _FDOutputStream(fd: childStdinFD)
    _childStdout = _FDInputStream(fd: childStdoutFD)
    _childStderr = _FDInputStream(fd: childStderrFD)
#endif
  }

  func _waitForChild() -> ProcessTerminationStatus {
#if os(Windows)
    let status = waitProcess(_process)
    _process = INVALID_HANDLE_VALUE

    _childStdin.close()
    _childStdout.close()
    _childStderr.close()
#else
    let status = posixWaitpid(_pid!)
    _pid = nil
    _childStdin.close()
    _childStdout.close()
    _childStderr.close()
    _childStdin = _FDOutputStream(fd: -1)
    _childStdout = _FDInputStream(fd: -1)
    _childStderr = _FDInputStream(fd: -1)
#endif
    return status
  }

  internal func _readFromChild(
    onStdoutLine: @escaping (String) -> (done: Bool, Void),
    onStderrLine: @escaping (String) -> (done: Bool, Void)
  ) {
#if os(Windows)
    let (_, stdoutThread) = _stdlib_thread_create_block({
      while !self._childStdout.isEOF {
        self._childStdout.read()
        while var line = self._childStdout.getline() {
          if let cr = line.firstIndex(of: "\r") {
            line.remove(at: cr)
          }
          var done: Bool
          (done: done, ()) = onStdoutLine(line)
          if done { return }
        }
      }
    }, ())

    let (_, stderrThread) = _stdlib_thread_create_block({
      while !self._childStderr.isEOF {
        self._childStderr.read()
        while var line = self._childStderr.getline() {
          if let cr = line.firstIndex(of: "\r") {
            line.remove(at: cr)
          }
          var done: Bool
          (done: done, ()) = onStderrLine(line)
          if done { return }
        }
      }
    }, ())

    let (_, _) = _stdlib_thread_join(stdoutThread!, Void.self)
    let (_, _) = _stdlib_thread_join(stderrThread!, Void.self)
#else
    var readfds = _stdlib_fd_set()
    var writefds = _stdlib_fd_set()
    var errorfds = _stdlib_fd_set()
    var done = false
    while !((_childStdout.isEOF && _childStderr.isEOF) || done) {
      readfds.zero()
      errorfds.zero()
      if !_childStdout.isEOF {
        readfds.set(_childStdout.fd)
        errorfds.set(_childStdout.fd)
      }
      if !_childStderr.isEOF {
        readfds.set(_childStderr.fd)
        errorfds.set(_childStderr.fd)
      }
      var ret: CInt
      repeat {
        ret = _stdlib_select(&readfds, &writefds, &errorfds, nil)
      } while ret == -1 && errno == EINTR
      if ret <= 0 {
        fatalError("select() returned an error")
      }
      if readfds.isset(_childStdout.fd) || errorfds.isset(_childStdout.fd) {
        _childStdout.read()
        while let line = _childStdout.getline() {
          (done: done, ()) = onStdoutLine(line)
        }
        continue
      }
      if readfds.isset(_childStderr.fd) || errorfds.isset(_childStderr.fd) {
        _childStderr.read()
        while let line = _childStderr.getline() {
          (done: done, ()) = onStderrLine(line)
        }
        continue
      }
    }
#endif
  }

  /// Returns the values of the corresponding variables in the child process.
  internal func _runTestInChild(
    _ testSuite: TestSuite,
    _ testName: String,
    parameter: Int?
  ) -> (anyExpectFailed: Bool, seenExpectCrash: Bool,
        status: ProcessTerminationStatus?,
        crashStdout: [Substring], crashStderr: [Substring]) {
#if os(Windows)
    if _process == INVALID_HANDLE_VALUE {
      _spawnChild()
    }
#else
    if _pid == nil {
      _spawnChild()
    }
#endif

    print("\(testSuite.name);\(testName)", terminator: "", to: &_childStdin)
    if let parameter = parameter {
      print(";", terminator: "", to: &_childStdin)
      print(parameter, terminator: "", to: &_childStdin)
    }
    print("", to: &_childStdin)

    let currentTest = testSuite._testByName(testName)
    if let stdinText = currentTest.stdinText {
      print(stdinText, terminator: "", to: &_childStdin)
    }
    if currentTest.stdinEndsWithEOF {
      _childStdin.close()
    }

    var stdoutSeenCrashDelimiter = false
    var stderrSeenCrashDelimiter = false
    var expectingPreCrashMessage = ""
    var stdoutEnd = false
    var stderrEnd = false
    var capturedCrashStdout: [Substring] = []
    var capturedCrashStderr: [Substring] = []
    var anyExpectFailedInChild = false

    func processLine(_ line: String, isStdout: Bool) -> (done: Bool, Void) {
      var line = line[...]
      if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
        let controlMessage =
            line[index..<line.endIndex].split(separator: ";",
                              omittingEmptySubsequences: false)
        switch controlMessage[1] {
        case "expectCrash":
          fallthrough
        case "expectCrash\r":
          if isStdout {
            stdoutSeenCrashDelimiter = true
            anyExpectFailedInChild = controlMessage[2] == "true"
          } else {
            stderrSeenCrashDelimiter = true
            expectingPreCrashMessage = String(controlMessage[2])
          }
        case "end":
          fallthrough
        case "end\r":
          if isStdout {
            stdoutEnd = true
            anyExpectFailedInChild = controlMessage[2] == "true"
          } else {
            stderrEnd = true
          }
        default:
          fatalError("unexpected message: \(controlMessage[1])")
        }
        line = line[line.startIndex..<index]
        if line.isEmpty {
#if os(Windows)
          return (done: isStdout ? stdoutEnd : stderrEnd, ())
#else
          return (done: stdoutEnd && stderrEnd, ())
#endif
        }
      }
      if !expectingPreCrashMessage.isEmpty
          && findSubstring(line, expectingPreCrashMessage) != nil {
        line = "OK: saw expected pre-crash message in \"\(line)\""[...]
        expectingPreCrashMessage = ""
      }
      if isStdout {
        if stdoutSeenCrashDelimiter {
          capturedCrashStdout.append(line)
        }
      } else {
        if stderrSeenCrashDelimiter {
          capturedCrashStderr.append(line)
          if findSubstring(line, _crashedPrefix) != nil {
            if !expectingPreCrashMessage.isEmpty {
              line = """
                      FAIL: saw expected "\(line.lowercased())", but without \
                      message "\(expectingPreCrashMessage)" before it
                      """[...]
              anyExpectFailedInChild = true
            }
            else {
              line = "OK: saw expected \"\(line.lowercased())\""[...]
            }
          }
        }
      }
      if isStdout {
        print("stdout>>> \(line)")
      } else {
        print("stderr>>> \(line)")
      }
#if os(Windows)
      return (done: isStdout ? stdoutEnd : stderrEnd, ())
#else
      return (done: stdoutEnd && stderrEnd, ())
#endif
    }

    _readFromChild(
      onStdoutLine: { processLine($0, isStdout: true) },
      onStderrLine: { processLine($0, isStdout: false) })

    // Check if the child has sent us "end" markers for the current test.
    if stdoutEnd && stderrEnd {
      var status: ProcessTerminationStatus?
      if testSuite._shouldShutDownChildProcess(forTestNamed: testName) {
        status = _waitForChild()
        switch status! {
        case .exit(0):
          status = nil
        default:
          ()
        }
      }
      return (
        anyExpectFailedInChild,
        stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter,
        status, capturedCrashStdout, capturedCrashStderr)
    }

    // We reached EOF on stdout and stderr and we did not see "end" markers, so
    // it looks like child crashed (of course it could have closed the file
    // descriptors, but we assume it did not, since it prevent further
    // communication with the parent).
    let status = _waitForChild()
    return (
      anyExpectFailedInChild,
      stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter,
      status, capturedCrashStdout, capturedCrashStderr)
  }

  internal func _shutdownChild() -> (failed: Bool, Void) {
#if os(Windows)
    if _process == INVALID_HANDLE_VALUE {
      // The child process is not running.  Report that it didn't fail during
      // shutdown.
      return (failed: false, ())
    }
#else
    if _pid == nil {
      // The child process is not running.  Report that it didn't fail during
      // shutdown.
      return (failed: false, ())
    }
#endif
    // If the child process expects an EOF, its stdin fd has already been closed and
    // it will shut itself down automatically.
    if !_childStdin.isClosed {
      print("\(_stdlibUnittestStreamPrefix);shutdown", to: &_childStdin)
    }

    var childCrashed = false

    func processLine(_ line: String, isStdout: Bool) -> (done: Bool, Void) {
      if isStdout {
        print("stdout>>> \(line)")
      } else {
        if findSubstring(line, _crashedPrefix) != nil {
          childCrashed = true
        }
        print("stderr>>> \(line)")
      }
      return (done: false, ())
    }

    _readFromChild(
      onStdoutLine: { processLine($0, isStdout: true) },
      onStderrLine: { processLine($0, isStdout: false) })

    let status = _waitForChild()
    switch status {
    case .exit(0):
      return (failed: childCrashed, ())
    default:
      print("Abnormal child process termination: \(status).")
      return (failed: true, ())
    }
  }

  internal enum _TestStatus {
    case skip([TestRunPredicate])
    case pass
    case fail
    case uxPass
    case xFail
  }

  internal func runOneTest(
    fullTestName: String,
    testSuite: TestSuite,
    test t: TestSuite._Test,
    testParameter: Int?
  ) -> _TestStatus {
    let activeSkips = t.getActiveSkipPredicates()
    if !activeSkips.isEmpty {
      return .skip(activeSkips)
    }

    let activeXFails = t.getActiveXFailPredicates()
    let expectXFail = !activeXFails.isEmpty
    let activeXFailsText = expectXFail ? " (XFAIL: \(activeXFails))" : ""
    print("[ RUN      ] \(fullTestName)\(activeXFailsText)")

    var expectCrash = false
    var childTerminationStatus: ProcessTerminationStatus?
    var crashStdout: [Substring] = []
    var crashStderr: [Substring] = []
    if _runTestsInProcess {
      if t.stdinText != nil {
        print("The test \(fullTestName) requires stdin input and can't be run in-process, marking as failed")
        _anyExpectFailed.store(true)
      } else if t.requiresOwnProcess {
        print("The test \(fullTestName) requires running in a child process and can't be run in-process, marking as failed.")
        _anyExpectFailed.store(true)
      } else {
        _anyExpectFailed.store(false)
        testSuite._runTest(name: t.name, parameter: testParameter)
      }
    } else {
      var anyExpectFailed = false
      (anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
       crashStderr) =
        _runTestInChild(testSuite, t.name, parameter: testParameter)
      _anyExpectFailed.store(anyExpectFailed)
    }

    // Determine if the test passed, not taking XFAILs into account.
    var testPassed = false
    switch (childTerminationStatus, expectCrash) {
    case (.none, false):
      testPassed = !_anyExpectFailed.load()

    case (.none, true):
      testPassed = false
      print("expecting a crash, but the test did not crash")

    case (.some, false):
      testPassed = false
      print("the test crashed unexpectedly")

    case (.some, true):
      testPassed = !_anyExpectFailed.load()
    }
    if testPassed && t.crashOutputMatches.count > 0 {
      // If we still think that the test passed, check if the crash
      // output matches our expectations.
      let crashOutput = crashStdout + crashStderr
      for expectedSubstring in t.crashOutputMatches {
        var found = false
        for s in crashOutput {
          if findSubstring(s, expectedSubstring) != nil {
            found = true
            break
          }
        }
        if !found {
          print("did not find expected string after crash: \(expectedSubstring.debugDescription)")
          testPassed = false
        }
      }
    }

    // Apply XFAILs.
    switch (testPassed, expectXFail) {
    case (true, false):
      return .pass

    case (true, true):
      return .uxPass

    case (false, false):
      return .fail

    case (false, true):
      return .xFail
    }
  }

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
  @available(SwiftStdlib 5.1, *)
  internal func runOneTestAsync(
    fullTestName: String,
    testSuite: TestSuite,
    test t: TestSuite._Test,
    testParameter: Int?
  ) async -> _TestStatus {
    let activeSkips = t.getActiveSkipPredicates()
    if !activeSkips.isEmpty {
      return .skip(activeSkips)
    }

    let activeXFails = t.getActiveXFailPredicates()
    let expectXFail = !activeXFails.isEmpty
    let activeXFailsText = expectXFail ? " (XFAIL: \(activeXFails))" : ""
    print("[ RUN      ] \(fullTestName)\(activeXFailsText)")

    var expectCrash = false
    var childTerminationStatus: ProcessTerminationStatus?
    var crashStdout: [Substring] = []
    var crashStderr: [Substring] = []
    if _runTestsInProcess {
      if t.stdinText != nil {
        print("The test \(fullTestName) requires stdin input and can't be run in-process, marking as failed")
        _anyExpectFailed.store(true)
      } else if t.requiresOwnProcess {
        print("The test \(fullTestName) requires running in a child process and can't be run in-process, marking as failed.")
        _anyExpectFailed.store(true)
      } else {
        _anyExpectFailed.store(false)
        await testSuite._runTestAsync(name: t.name, parameter: testParameter)
      }
    } else {
      var anyExpectFailed = false
      (anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
       crashStderr) =
        _runTestInChild(testSuite, t.name, parameter: testParameter)
      _anyExpectFailed.store(anyExpectFailed)
    }

    // Determine if the test passed, not taking XFAILs into account.
    var testPassed = false
    switch (childTerminationStatus, expectCrash) {
    case (.none, false):
      testPassed = !_anyExpectFailed.load()

    case (.none, true):
      testPassed = false
      print("expecting a crash, but the test did not crash")

    case (.some, false):
      testPassed = false
      print("the test crashed unexpectedly")

    case (.some, true):
      testPassed = !_anyExpectFailed.load()
    }
    if testPassed && t.crashOutputMatches.count > 0 {
      // If we still think that the test passed, check if the crash
      // output matches our expectations.
      let crashOutput = crashStdout + crashStderr
      for expectedSubstring in t.crashOutputMatches {
        var found = false
        for s in crashOutput {
          if findSubstring(s, expectedSubstring) != nil {
            found = true
            break
          }
        }
        if !found {
          print("did not find expected string after crash: \(expectedSubstring.debugDescription)")
          testPassed = false
        }
      }
    }

    // Apply XFAILs.
    switch (testPassed, expectXFail) {
    case (true, false):
      return .pass

    case (true, true):
      return .uxPass

    case (false, false):
      return .fail

    case (false, true):
      return .xFail
    }
  }
#endif


  func run() {
    if let filter = _filter {
      print("StdlibUnittest: using filter: \(filter)")
    }
    for testSuite in _allTestSuites {
      var uxpassedTests: [String] = []
      var failedTests: [String] = []
      var skippedTests: [String] = []
      for t in testSuite._tests {
        for testParameter in t.parameterValues {
          var testName = t.name
          if let testParameter = testParameter {
            testName += "/"
            testName += String(testParameter)
          }
          let fullTestName = "\(testSuite.name).\(testName)"
          if let filter = _filter,
             findSubstring(fullTestName, filter) == nil {

            continue
          }

          switch runOneTest(
            fullTestName: fullTestName,
            testSuite: testSuite,
            test: t,
            testParameter: testParameter
          ) {
          case .skip(let activeSkips):
            skippedTests.append(testName)
            print("[ SKIP     ] \(fullTestName) (skip: \(activeSkips))")

          case .pass:
            print("[       OK ] \(fullTestName)")

          case .uxPass:
            uxpassedTests.append(testName)
            print("[   UXPASS ] \(fullTestName)")

          case .fail:
            failedTests.append(testName)
            print("[     FAIL ] \(fullTestName)")

          case .xFail:
            print("[    XFAIL ] \(fullTestName)")
          }
        }
      }

      if !uxpassedTests.isEmpty || !failedTests.isEmpty {
        print("\(testSuite.name): Some tests failed, aborting")
        print("UXPASS: \(uxpassedTests)")
        print("FAIL: \(failedTests)")
        print("SKIP: \(skippedTests)")
        if !uxpassedTests.isEmpty {
          _printDebuggingAdvice(uxpassedTests[0])
        }
        if !failedTests.isEmpty {
          _printDebuggingAdvice(failedTests[0])
        }
        _testSuiteFailedCallback()
      } else {
        print("\(testSuite.name): All tests passed")
        if testSuite._tests.isEmpty {
          print("WARNING: SUITE '\(testSuite.name)' CONTAINED NO TESTS! NO TESTS WERE EXECUTED!")
        }
      }
    }
    let (failed: failedOnShutdown, ()) = _shutdownChild()
    if failedOnShutdown {
      print("The child process failed during shutdown, aborting.")
      _testSuiteFailedCallback()
    }
  }

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
  @available(SwiftStdlib 5.1, *)
  func runAsync() async {
    if let filter = _filter {
      print("StdlibUnittest: using filter: \(filter)")
    }
    for testSuite in _allTestSuites {
      var uxpassedTests: [String] = []
      var failedTests: [String] = []
      var skippedTests: [String] = []
      for t in testSuite._tests {
        for testParameter in t.parameterValues {
          var testName = t.name
          if let testParameter = testParameter {
            testName += "/"
            testName += String(testParameter)
          }
          let fullTestName = "\(testSuite.name).\(testName)"
          if let filter = _filter,
             findSubstring(fullTestName, filter) == nil {

            continue
          }

          switch await runOneTestAsync(
            fullTestName: fullTestName,
            testSuite: testSuite,
            test: t,
            testParameter: testParameter
          ) {
          case .skip(let activeSkips):
            skippedTests.append(testName)
            print("[ SKIP     ] \(fullTestName) (skip: \(activeSkips))")

          case .pass:
            print("[       OK ] \(fullTestName)")

          case .uxPass:
            uxpassedTests.append(testName)
            print("[   UXPASS ] \(fullTestName)")

          case .fail:
            failedTests.append(testName)
            print("[     FAIL ] \(fullTestName)")

          case .xFail:
            print("[    XFAIL ] \(fullTestName)")
          }
        }
      }

      if !uxpassedTests.isEmpty || !failedTests.isEmpty {
        print("\(testSuite.name): Some tests failed, aborting")
        print("UXPASS: \(uxpassedTests)")
        print("FAIL: \(failedTests)")
        print("SKIP: \(skippedTests)")
        if !uxpassedTests.isEmpty {
          _printDebuggingAdvice(uxpassedTests[0])
        }
        if !failedTests.isEmpty {
          _printDebuggingAdvice(failedTests[0])
        }
        _testSuiteFailedCallback()
      } else {
        print("\(testSuite.name): All tests passed")
      }
    }
    let (failed: failedOnShutdown, ()) = _shutdownChild()
    if failedOnShutdown {
      print("The child process failed during shutdown, aborting.")
      _testSuiteFailedCallback()
    }
  }
#endif

}

// Track repeated calls to runAllTests() and/or runNoTests().
// Complain if a file runs no tests without calling runNoTests().
struct PersistentState {
  static var runAllTestsWasCalled: Bool = false
  static var runNoTestsWasCalled: Bool = false
  static var ranSomething: Bool = false
  static var complaintInstalled = false
  static var hashingKeyOverridden = false

  static func complainIfNothingRuns() {
    if !complaintInstalled {
      complaintInstalled = true
      atexit {
        if !PersistentState.ranSomething {
          print("Ran no tests and runNoTests() was not called. Aborting. ")
          print("Did you forget to call runAllTests()?")
          _testSuiteFailedCallback()
        }
      }
    }
  }
}


// Call runNoTests() if you want to deliberately run no tests.
public func runNoTests() {
  if PersistentState.runAllTestsWasCalled {
    print("runNoTests() called after runAllTests(). Aborting.")
    _testSuiteFailedCallback()
    return
  }
  if PersistentState.runNoTestsWasCalled {
    print("runNoTests() called twice. Aborting.")
    _testSuiteFailedCallback()
    return
  }
  PersistentState.runNoTestsWasCalled = true
  PersistentState.ranSomething = true
}

public func runAllTests() {
  if PersistentState.runNoTestsWasCalled {
    print("runAllTests() called after runNoTests(). Aborting.")
    _testSuiteFailedCallback()
    return
  }
  if PersistentState.runAllTestsWasCalled {
    print("runAllTests() called twice. Aborting.")
    _testSuiteFailedCallback()
    return
  }
  PersistentState.runAllTestsWasCalled = true
  PersistentState.ranSomething = true

#if _runtime(_ObjC)
  autoreleasepool {
    _stdlib_initializeReturnAutoreleased()
  }
#endif

  let _isChildProcess: Bool =
    CommandLine.arguments.contains("--stdlib-unittest-run-child")

  if _isChildProcess {
    _childProcess()
  } else {
    var runTestsInProcess: Bool = !platformSupportsChildProcesses
    var filter: String?
    var args = [String]()
    var i = 0
    i += 1 // Skip the name of the executable.
    while i < CommandLine.arguments.count {
      let arg = CommandLine.arguments[i]
      if arg == "--stdlib-unittest-in-process" {
        runTestsInProcess = true
        i += 1
        continue
      }
      if arg == "--stdlib-unittest-filter" {
        filter = CommandLine.arguments[i + 1]
        i += 2
        continue
      }
      if arg == "--help" {
        let message =
"optional arguments:\n" +
"--stdlib-unittest-in-process\n" +
"                        run tests in-process without intercepting crashes.\n" +
"                        Useful for running under a debugger.\n" +
"--stdlib-unittest-filter FILTER-STRING\n" +
"                        only run tests whose names contain FILTER-STRING as\n" +
"                        a substring."
        print(message)
        return
      }

      // Pass through unparsed arguments to the child process.
      args.append(CommandLine.arguments[i])

      i += 1
    }

    let parent = _ParentProcess(
      runTestsInProcess: runTestsInProcess, args: args, filter: filter)
    parent.run()
  }
}

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
@available(SwiftStdlib 5.1, *)
public func runAllTestsAsync() async {
  if PersistentState.runNoTestsWasCalled {
    print("runAllTests() called after runNoTests(). Aborting.")
    _testSuiteFailedCallback()
    return
  }
  if PersistentState.runAllTestsWasCalled {
    print("runAllTests() called twice. Aborting.")
    _testSuiteFailedCallback()
    return
  }
  PersistentState.runAllTestsWasCalled = true
  PersistentState.ranSomething = true

#if _runtime(_ObjC)
  autoreleasepool {
    _stdlib_initializeReturnAutoreleased()
  }
#endif

  let _isChildProcess: Bool =
    CommandLine.arguments.contains("--stdlib-unittest-run-child")

  if _isChildProcess {
    await _childProcessAsync()
  } else {
    var runTestsInProcess: Bool = !platformSupportsChildProcesses
    var filter: String?
    var args = [String]()
    var i = 0
    i += 1 // Skip the name of the executable.
    while i < CommandLine.arguments.count {
      let arg = CommandLine.arguments[i]
      if arg == "--stdlib-unittest-in-process" {
        runTestsInProcess = true
        i += 1
        continue
      }
      if arg == "--stdlib-unittest-filter" {
        filter = CommandLine.arguments[i + 1]
        i += 2
        continue
      }
      if arg == "--help" {
        let message =
"optional arguments:\n" +
"--stdlib-unittest-in-process\n" +
"                        run tests in-process without intercepting crashes.\n" +
"                        Useful for running under a debugger.\n" +
"--stdlib-unittest-filter FILTER-STRING\n" +
"                        only run tests whose names contain FILTER-STRING as\n" +
"                        a substring."
        print(message)
        return
      }

      // Pass through unparsed arguments to the child process.
      args.append(CommandLine.arguments[i])

      i += 1
    }

    let parent = _ParentProcess(
      runTestsInProcess: runTestsInProcess, args: args, filter: filter)
    await parent.runAsync()
  }
}
#endif

#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER

@_silgen_name("_swift_leaks_startTrackingObjects")
func startTrackingObjects(_: UnsafePointer<CChar>)
@_silgen_name("_swift_leaks_stopTrackingObjects")
func stopTrackingObjects(_: UnsafePointer<CChar>) -> Int

#endif

public final class TestSuite {
  public init(_ name: String) {
    self.name = name
    precondition(
      _testNameToIndex[name] == nil,
      "test suite with the same name already exists")
    _allTestSuites.append(self)
    _testSuiteNameToIndex[name] = _allTestSuites.count - 1
    PersistentState.complainIfNothingRuns()
  }

  // This method is prohibited from inlining because inlining the test harness
  // into the test is not interesting from the runtime performance perspective.
  // And it does not really make the test cases more effectively at testing the
  // optimizer from a correctness prospective. On the contrary, it sometimes
  // severely affects the compile time of the test code.
  @inline(never)
  public func test(
    _ name: String,
    file: String = #file, line: UInt = #line,
    _ testFunction: @escaping () -> Void
  ) {
    _TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
    .code(testFunction)
  }

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
  // This method is prohibited from inlining because inlining the test harness
  // into the test is not interesting from the runtime performance perspective.
  // And it does not really make the test cases more effectively at testing the
  // optimizer from a correctness prospective. On the contrary, it sometimes
  // severely affects the compile time of the test code.
  @inline(never)
  public func test(
    _ name: String,
    file: String = #file, line: UInt = #line,
    _ testFunction: @escaping () async -> Void
  ) {
    _TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
    .code(testFunction)
  }
#endif

  // This method is prohibited from inlining because inlining the test harness
  // into the test is not interesting from the runtime performance perspective.
  // And it does not really make the test cases more effectively at testing the
  // optimizer from a correctness prospective. On the contrary, it sometimes
  // severely affects the compile time of the test code.
  @inline(never)
  public func test(
    _ name: String, file: String = #file, line: UInt = #line
  ) -> _TestBuilder {
    return _TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
  }

  public func setUp(_ code: @escaping () -> Void) {
    precondition(_testSetUpCode == nil, "set-up code already set")
    _testSetUpCode = code
  }

  public func tearDown(_ code: @escaping () -> Void) {
    precondition(_testTearDownCode == nil, "tear-down code already set")
    _testTearDownCode = code
  }

  func _runTest(name testName: String, parameter: Int?) {
    PersistentState.ranSomething = true
    for r in _allResettables {
      r.reset()
    }
    LifetimeTracked.instances = 0
    if let f = _testSetUpCode {
      f()
    }
    let test = _testByName(testName)

#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
    startTrackingObjects(name)
#endif

    switch test.code {
    case .single(let code):
      precondition(
        parameter == nil,
        "can't pass parameters to non-parameterized tests")
      code()
    case .parameterized(code: let code, _):
      code(parameter!)
#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
    case .singleAsync(_):
      fatalError("Cannot call async code, use `runAllTestsAsync`")
    case .parameterizedAsync(code: _, _):
      fatalError("Cannot call async code, use `runAllTestsAsync`")
#endif
    }

#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
    _ = stopTrackingObjects(name)
#endif

    if let f = _testTearDownCode {
      f()
    }
    expectEqual(
      0, LifetimeTracked.instances, "Found leaked LifetimeTracked instances.",
      file: test.testLoc.file, line: test.testLoc.line)
  }

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
  @available(SwiftStdlib 5.1, *)
  func _runTestAsync(name testName: String, parameter: Int?) async {
    PersistentState.ranSomething = true
    for r in _allResettables {
      r.reset()
    }
    LifetimeTracked.instances = 0
    if let f = _testSetUpCode {
      f()
    }
    let test = _testByName(testName)

#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
    startTrackingObjects(name)
#endif

    switch test.code {
    case .single(let code):
      precondition(
        parameter == nil,
        "can't pass parameters to non-parameterized tests")
      code()
    case .parameterized(code: let code, _):
      code(parameter!)
#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
    case .singleAsync(let code):
      precondition(
        parameter == nil,
        "can't pass parameters to non-parameterized tests")
      await code()
    case .parameterizedAsync(code: let code, _):
      await code(parameter!)
#endif
    }

#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
    _ = stopTrackingObjects(name)
#endif

    if let f = _testTearDownCode {
      f()
    }
    expectEqual(
      0, LifetimeTracked.instances, "Found leaked LifetimeTracked instances.",
      file: test.testLoc.file, line: test.testLoc.line)
  }
#endif

  func _testByName(_ testName: String) -> _Test {
    return _tests[_testNameToIndex[testName]!]
  }

  /// Determines if we should shut down the current test process, i.e. if this
  /// test or the next test requires executing in its own process.
  func _shouldShutDownChildProcess(forTestNamed testName: String) -> Bool {
    let index = _testNameToIndex[testName]!
    if index == _tests.count - 1 { return false }
    let currentTest = _tests[index]
    let nextTest = _tests[index + 1]
    if !currentTest.canReuseChildProcessAfterTest { return true }
    return currentTest.requiresOwnProcess || nextTest.requiresOwnProcess
  }

  internal enum _TestCode {
    case single(code: () -> Void)
    case parameterized(code: (Int) -> Void, count: Int)
#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
    case singleAsync(code: () async -> Void)
    case parameterizedAsync(code: (Int) async -> Void, count: Int)
#endif
  }

  internal struct _Test {
    let name: String
    let testLoc: SourceLoc
    let xfail: [TestRunPredicate]
    let skip: [TestRunPredicate]
    let stdinText: String?
    let stdinEndsWithEOF: Bool
    let crashOutputMatches: [String]
    let code: _TestCode
    let requiresOwnProcess: Bool

    /// Whether the test harness should stop reusing the child process after
    /// running this test.
    var canReuseChildProcessAfterTest: Bool {
      return stdinText == nil
    }

    func getActiveXFailPredicates() -> [TestRunPredicate] {
      return xfail.filter { $0.evaluate() }
    }

    func getActiveSkipPredicates() -> [TestRunPredicate] {
      return skip.filter { $0.evaluate() }
    }

    var parameterValues: [Int?] {
      switch code {
      case .single:
        return [nil]
      case .parameterized(code: _, count: let count):
        return Array(0..<count)
#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
      case .singleAsync:
        return [nil]
      case .parameterizedAsync(code: _, count: let count):
        return Array(0..<count)
#endif
      }
    }
  }

  public struct _TestBuilder {
    let _testSuite: TestSuite
    var _name: String
    var _data: _Data = _Data()

    internal final class _Data {
      var _xfail: [TestRunPredicate] = []
      var _skip: [TestRunPredicate] = []
      var _stdinText: String?
      var _stdinEndsWithEOF: Bool = false
      var _crashOutputMatches: [String] = []
      var _testLoc: SourceLoc?
      var _requiresOwnProcess: Bool = false
    }

    init(testSuite: TestSuite, name: String, loc: SourceLoc) {
      _testSuite = testSuite
      _name = name
      _data._testLoc = loc
    }

    public func xfail(_ predicate: TestRunPredicate) -> _TestBuilder {
      _data._xfail.append(predicate)
      return self
    }

    public func skip(_ predicate: TestRunPredicate) -> _TestBuilder {
      _data._skip.append(predicate)
      return self
    }

    public func require(_ stdlibVersion: StdlibVersion) -> _TestBuilder {
      require(TestRequirement.minimumStdlib(stdlibVersion))
    }

    public func require(
      _ requirement: TestRequirement
    ) -> _TestBuilder {
      _data._skip.append(.missingRequirement(requirement))
      return self
    }

    public func stdin(_ stdinText: String, eof: Bool = false) -> _TestBuilder {
      _data._stdinText = stdinText
      _data._stdinEndsWithEOF = eof
      return self
    }

    public func crashOutputMatches(
      _ string: String,
      when predicate: Bool = true
    ) -> _TestBuilder {
      if predicate {
        _data._crashOutputMatches.append(string)
      }
      return self
    }

    public func requireOwnProcess() -> _TestBuilder {
      _data._requiresOwnProcess = true
      return self
    }

    internal func _build(_ testCode: _TestCode) {
      _testSuite._tests.append(
        _Test(
          name: _name, testLoc: _data._testLoc!, xfail: _data._xfail,
          skip: _data._skip,
          stdinText: _data._stdinText,
          stdinEndsWithEOF: _data._stdinEndsWithEOF,
          crashOutputMatches: _data._crashOutputMatches,
          code: testCode,
          requiresOwnProcess: _data._requiresOwnProcess))
      _testSuite._testNameToIndex[_name] = _testSuite._tests.count - 1
    }

    public func code(_ testFunction: @escaping () -> Void) {
      _build(.single(code: testFunction))
    }

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
    public func code(_ testFunction: @escaping () async -> Void) {
      _build(.singleAsync(code: testFunction))
    }
#endif

    public func forEach<Data>(
      in parameterSets: [Data],
      testFunction: @escaping (Data) -> Void
    ) {
      _build(.parameterized(
        code: { (i: Int) in testFunction(parameterSets[i]) },
        count: parameterSets.count))
    }

#if SWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY
    public func forEach<Data>(
      in parameterSets: [Data],
      testFunction: @escaping (Data) async -> Void
    ) {
      _build(.parameterizedAsync(
        code: { (i: Int) in await testFunction(parameterSets[i]) },
        count: parameterSets.count))
    }
#endif

  }

  var name: String
  var _tests: [_Test] = []

  /// Code that is run before every test.
  var _testSetUpCode: (() -> Void)?

  /// Code that is run after every test.
  var _testTearDownCode: (() -> Void)?

  /// Maps test name to index in `_tests`.
  var _testNameToIndex: [String : Int] = [:]
}

#if canImport(Darwin)
#if _runtime(_ObjC)
func _getSystemVersionPlistProperty(_ propertyName: String) -> String? {
  return NSDictionary(contentsOfFile: "/System/Library/CoreServices/SystemVersion.plist")?[propertyName] as? String
}
#else
func _getSystemVersionPlistProperty(_ propertyName: String) -> String? {
  var count = 0
  sysctlbyname("kern.osproductversion", nil, &count, nil, 0)
  return withUnsafeTemporaryAllocation(of: CChar.self, capacity: count) {
    sysctlbyname("kern.osproductversion", $0.baseAddress, &count, nil, 0)
    return String(cString: $0.baseAddress!)
  }
}
#endif
#endif

public enum StdlibVersion: String {
  case stdlib_5_7  = "5.7"
  case stdlib_5_8  = "5.8"
  case stdlib_5_9  = "5.9"
  case stdlib_5_10 = "5.10"
  case stdlib_6_0  = "6.0"
  case stdlib_6_1  = "6.1"
  case stdlib_6_2  = "6.2"
  case stdlib_6_3  = "6.3"
  case stdlib_6_4  = "6.4"
  case stdlib_6_5  = "6.5"

  var isAvailable: Bool {
    switch self {
    case .stdlib_5_7:
      return if #available(SwiftStdlib 5.7, *)  { true } else { false }
    case .stdlib_5_8:
      return if #available(SwiftStdlib 5.8, *)  { true } else { false }
    case .stdlib_5_9:
      return if #available(SwiftStdlib 5.9, *)  { true } else { false }
    case .stdlib_5_10:
      return if #available(SwiftStdlib 5.10, *) { true } else { false }
    case .stdlib_6_0:
      return if #available(SwiftStdlib 6.0, *)  { true } else { false }
    case .stdlib_6_1:
      return if #available(SwiftStdlib 6.1, *)  { true } else { false }
    case .stdlib_6_2:
      return if #available(SwiftStdlib 6.2, *)  { true } else { false }
    case .stdlib_6_3:
      return if #available(SwiftStdlib 6.3, *)  { true } else { false }
    case .stdlib_6_4:
      return if #available(SwiftStdlib 6.4, *)  { true } else { false }
    case .stdlib_6_5:
      return if #available(SwiftStdlib 6.5, *)  { true } else { false }
    }
  }
}

public enum TestRequirement: CustomStringConvertible {
  case minimumStdlib(StdlibVersion)
  case crashTesting

  var isMissing: Bool {
    switch self {
    case .minimumStdlib(let version):
      !version.isAvailable
    case .crashTesting:
      switch _getRunningOSVersion() {
      case .wasi, .emscripten:
        true
      default:
        false
      }
    }
  }

  public var description: String {
    switch self {
    case .crashTesting: "crash testing"
    case .minimumStdlib(let version): "standard library version \(version)"
    }
  }
}

public enum OSVersion : CustomStringConvertible {
  case osx(major: Int, minor: Int, bugFix: Int)
  case iOS(major: Int, minor: Int, bugFix: Int)
  case tvOS(major: Int, minor: Int, bugFix: Int)
  case watchOS(major: Int, minor: Int, bugFix: Int)
  case visionOS(major: Int, minor: Int, bugFix: Int)
  case iOSSimulator
  case tvOSSimulator
  case watchOSSimulator
  case visionOSSimulator
  case linux
  case freeBSD
  case openBSD
  case android
  case ps4
  case windowsCygnus
  case windows
  case haiku
  case wasi
  case emscripten

  public var description: String {
    switch self {
    case .osx(let major, let minor, let bugFix):
      return "OS X \(major).\(minor).\(bugFix)"
    case .iOS(let major, let minor, let bugFix):
      return "iOS \(major).\(minor).\(bugFix)"
    case .tvOS(let major, let minor, let bugFix):
      return "TVOS \(major).\(minor).\(bugFix)"
    case .watchOS(let major, let minor, let bugFix):
      return "watchOS \(major).\(minor).\(bugFix)"
    case .visionOS(let major, let minor, let bugFix):
      return "visionOS \(major).\(minor).\(bugFix)"
    case .iOSSimulator:
      return "iOSSimulator"
    case .tvOSSimulator:
      return "TVOSSimulator"
    case .watchOSSimulator:
      return "watchOSSimulator"
    case .visionOSSimulator:
      return "visionOSSimulator"
    case .linux:
      return "Linux"
    case .freeBSD:
      return "FreeBSD"
    case .openBSD:
      return "OpenBSD"
    case .ps4:
      return "PS4"
    case .android:
      return "Android"
    case .windowsCygnus:
      return "Cygwin"
    case .windows:
      return "Windows"
    case .haiku:
      return "Haiku"
    case .wasi:
      return "WASI"
    case .emscripten:
      return "Emscripten"
    }
  }
}

func _parseDottedVersion(_ s: String) -> [Int] {
  return Array(s._split(separator: ".").lazy.map { Int($0)! })
}

public func _parseDottedVersionTriple(_ s: String) -> (Int, Int, Int) {
  let array = _parseDottedVersion(s)
  if array.count >= 4 {
    fatalError("unexpected version")
  }
  return (
    array.count >= 1 ? array[0] : 0,
    array.count >= 2 ? array[1] : 0,
    array.count >= 3 ? array[2] : 0)
}

func _getOSVersion() -> OSVersion {
#if os(iOS) && targetEnvironment(simulator)
  // On simulator, the plist file that we try to read turns out to be host's
  // plist file, which indicates OS X.
  //
  // FIXME: how to get the simulator version *without* UIKit?
  return .iOSSimulator
#elseif os(tvOS) && targetEnvironment(simulator)
  return .tvOSSimulator
#elseif os(watchOS) && targetEnvironment(simulator)
  return .watchOSSimulator
#elseif os(visionOS) && targetEnvironment(simulator)
  return .visionOSSimulator
#elseif os(Linux)
  return .linux
#elseif os(FreeBSD)
  return .freeBSD
#elseif os(OpenBSD)
  return .openBSD
#elseif os(PS4)
  return .ps4
#elseif os(Android)
  return .android
#elseif os(Cygwin)
  return .windowsCygnus
#elseif os(Windows)
  return .windows
#elseif os(Haiku)
  return .haiku
#elseif os(WASI)
  return .wasi
#elseif os(Emscripten)
  return .emscripten
#else
  let productVersion = _getSystemVersionPlistProperty("ProductVersion")!
  let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion)
  #if os(macOS)
  return .osx(major: major, minor: minor, bugFix: bugFix)
  #elseif os(iOS)
  return .iOS(major: major, minor: minor, bugFix: bugFix)
  #elseif os(tvOS)
  return .tvOS(major: major, minor: minor, bugFix: bugFix)
  #elseif os(watchOS)
  return .watchOS(major: major, minor: minor, bugFix: bugFix)
  #elseif os(visionOS)
  return .visionOS(major: major, minor: minor, bugFix: bugFix)
  #else
  fatalError("could not determine OS version")
  #endif
#endif
}

var _runningOSVersion: OSVersion = _getOSVersion()
var _overrideOSVersion: OSVersion?

/// Override the OS version for testing.
public func _setOverrideOSVersion(_ v: OSVersion) {
  _overrideOSVersion = v
}

func _getRunningOSVersion() -> OSVersion {
  // Allow overriding the OS version for testing.
  return _overrideOSVersion ?? _runningOSVersion
}

public enum TestRunPredicate : CustomStringConvertible {
  case custom(() -> Bool, reason: String)

  case always(/*reason:*/ String)
  case never

  case osxAny(/*reason:*/ String)
  case osxMajor(Int, reason: String)
  case osxMinor(Int, Int, reason: String)
  case osxMinorRange(Int, ClosedRange<Int>, reason: String)
  case osxBugFix(Int, Int, Int, reason: String)
  case osxBugFixRange(Int, Int, ClosedRange<Int>, reason: String)

  case iOSAny(/*reason:*/ String)
  case iOSMajor(Int, reason: String)
  case iOSMajorRange(ClosedRange<Int>, reason: String)
  case iOSMinor(Int, Int, reason: String)
  case iOSMinorRange(Int, ClosedRange<Int>, reason: String)
  case iOSBugFix(Int, Int, Int, reason: String)
  case iOSBugFixRange(Int, Int, ClosedRange<Int>, reason: String)

  case iOSSimulatorAny(/*reason:*/ String)

  case tvOSAny(/*reason:*/ String)
  case tvOSMajor(Int, reason: String)
  case tvOSMajorRange(ClosedRange<Int>, reason: String)
  case tvOSMinor(Int, Int, reason: String)
  case tvOSMinorRange(Int, ClosedRange<Int>, reason: String)
  case tvOSBugFix(Int, Int, Int, reason: String)
  case tvOSBugFixRange(Int, Int, ClosedRange<Int>, reason: String)

  case tvOSSimulatorAny(/*reason:*/ String)

  case watchOSAny(/*reason:*/ String)
  case watchOSMajor(Int, reason: String)
  case watchOSMajorRange(ClosedRange<Int>, reason: String)
  case watchOSMinor(Int, Int, reason: String)
  case watchOSMinorRange(Int, ClosedRange<Int>, reason: String)
  case watchOSBugFix(Int, Int, Int, reason: String)
  case watchOSBugFixRange(Int, Int, ClosedRange<Int>, reason: String)

  case watchOSSimulatorAny(/*reason:*/ String)

  case visionOSAny(/*reason:*/ String)
  case visionOSMajor(Int, reason: String)
  case visionOSMajorRange(ClosedRange<Int>, reason: String)
  case visionOSMinor(Int, Int, reason: String)
  case visionOSMinorRange(Int, ClosedRange<Int>, reason: String)
  case visionOSBugFix(Int, Int, Int, reason: String)
  case visionOSBugFixRange(Int, Int, ClosedRange<Int>, reason: String)

  case visionOSSimulatorAny(/*reason:*/ String)

  case linuxAny(reason: String)

  case freeBSDAny(reason: String)

  case ps4Any(reason: String)

  case androidAny(reason: String)

  case windowsAny(reason: String)

  case windowsCygnusAny(reason: String)

  case haikuAny(reason: String)

  case wasiAny(reason: String)

  case emscriptenAny(reason: String)

  case objCRuntime(/*reason:*/ String)
  case nativeRuntime(/*reason:*/ String)

  case minimumStdlib(StdlibVersion)

  case missingRequirement(TestRequirement)

  public var description: String {
    switch self {
    case .custom(_, let reason):
      return "Custom(reason: \(reason))"

    case .always(let reason):
      return "Always(reason: \(reason))"
    case .never:
      return ""

    case .osxAny(let reason):
      return "osx(*, reason: \(reason))"
    case .osxMajor(let major, let reason):
      return "osx(\(major).*, reason: \(reason))"
    case .osxMinor(let major, let minor, let reason):
      return "osx(\(major).\(minor), reason: \(reason))"
    case .osxMinorRange(let major, let minorRange, let reason):
      return "osx(\(major).[\(minorRange)], reason: \(reason))"
    case .osxBugFix(let major, let minor, let bugFix, let reason):
      return "osx(\(major).\(minor).\(bugFix), reason: \(reason))"
    case .osxBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "osx(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case .iOSAny(let reason):
      return "iOS(*, reason: \(reason))"
    case .iOSMajor(let major, let reason):
      return "iOS(\(major).*, reason: \(reason))"
    case .iOSMajorRange(let range, let reason):
      return "iOS([\(range)], reason: \(reason))"
    case .iOSMinor(let major, let minor, let reason):
      return "iOS(\(major).\(minor), reason: \(reason))"
    case .iOSMinorRange(let major, let minorRange, let reason):
      return "iOS(\(major).[\(minorRange)], reason: \(reason))"
    case .iOSBugFix(let major, let minor, let bugFix, let reason):
      return "iOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case .iOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "iOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case .iOSSimulatorAny(let reason):
      return "iOSSimulatorAny(*, reason: \(reason))"

    case .tvOSAny(let reason):
      return "tvOS(*, reason: \(reason))"
    case .tvOSMajor(let major, let reason):
      return "tvOS(\(major).*, reason: \(reason))"
    case .tvOSMajorRange(let range, let reason):
      return "tvOS([\(range)], reason: \(reason))"
    case .tvOSMinor(let major, let minor, let reason):
      return "tvOS(\(major).\(minor), reason: \(reason))"
    case .tvOSMinorRange(let major, let minorRange, let reason):
      return "tvOS(\(major).[\(minorRange)], reason: \(reason))"
    case .tvOSBugFix(let major, let minor, let bugFix, let reason):
      return "tvOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case .tvOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "tvOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case .tvOSSimulatorAny(let reason):
      return "tvOSSimulatorAny(*, reason: \(reason))"

    case .watchOSAny(let reason):
      return "watchOS(*, reason: \(reason))"
    case .watchOSMajor(let major, let reason):
      return "watchOS(\(major).*, reason: \(reason))"
    case .watchOSMajorRange(let range, let reason):
      return "watchOS([\(range)], reason: \(reason))"
    case .watchOSMinor(let major, let minor, let reason):
      return "watchOS(\(major).\(minor), reason: \(reason))"
    case .watchOSMinorRange(let major, let minorRange, let reason):
      return "watchOS(\(major).[\(minorRange)], reason: \(reason))"
    case .watchOSBugFix(let major, let minor, let bugFix, let reason):
      return "watchOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case .watchOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "watchOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case .watchOSSimulatorAny(let reason):
      return "watchOSSimulatorAny(*, reason: \(reason))"

    case .visionOSAny(let reason):
      return "visionOS(*, reason: \(reason))"
    case .visionOSMajor(let major, let reason):
      return "visionOS(\(major).*, reason: \(reason))"
    case .visionOSMajorRange(let range, let reason):
      return "visionOS([\(range)], reason: \(reason))"
    case .visionOSMinor(let major, let minor, let reason):
      return "visionOS(\(major).\(minor), reason: \(reason))"
    case .visionOSMinorRange(let major, let minorRange, let reason):
      return "visionOS(\(major).[\(minorRange)], reason: \(reason))"
    case .visionOSBugFix(let major, let minor, let bugFix, let reason):
      return "visionOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case .visionOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "visionOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case .visionOSSimulatorAny(let reason):
      return "visionOSSimulatorAny(*, reason: \(reason))"

    case .linuxAny(reason: let reason):
      return "linuxAny(*, reason: \(reason))"

    case .androidAny(reason: let reason):
      return "androidAny(*, reason: \(reason))"

    case .freeBSDAny(reason: let reason):
      return "freeBSDAny(*, reason: \(reason))"

    case .ps4Any(reason: let reason):
      return "ps4Any(*, reason: \(reason))"

    case .windowsAny(reason: let reason):
      return "windowsAny(*, reason: \(reason))"

    case .windowsCygnusAny(reason: let reason):
      return "windowsCygnusAny(*, reason: \(reason))"

    case .haikuAny(reason: let reason):
      return "haikuAny(*, reason: \(reason))"

    case .wasiAny(reason: let reason):
      return "wasiAny(*, reason: \(reason))"

    case .emscriptenAny(reason: let reason):
      return "emscriptenAny(*, reason: \(reason))"

    case .objCRuntime(let reason):
      return "Objective-C runtime, reason: \(reason))"
    case .nativeRuntime(let reason):
      return "Native runtime (no ObjC), reason: \(reason))"
      
    case .minimumStdlib(let version):
      return "Requires Swift \(version.rawValue)'s standard library"

    case .missingRequirement(let requirement):
      return "Requires \(requirement)"
    }
  }

  public func evaluate() -> Bool {
    switch self {
    case .custom(let predicate, _):
      return predicate()

    case .always:
      return true
    case .never:
      return false

    case .osxAny:
      switch _getRunningOSVersion() {
      case .osx:
        return true
      default:
        return false
      }

    case .osxMajor(let major, _):
      switch _getRunningOSVersion() {
      case .osx(major, _, _):
        return true
      default:
        return false
      }

    case .osxMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .osx(major, minor, _):
        return true
      default:
        return false
      }

    case .osxMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .osx(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case .osxBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .osx(major, minor, bugFix):
        return true
      default:
        return false
      }

    case .osxBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .osx(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case .iOSAny:
      switch _getRunningOSVersion() {
      case .iOS:
        return true
      default:
        return false
      }

    case .iOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .iOS(major, _, _):
        return true
      default:
        return false
      }

    case .iOSMajorRange(let range, _):
      switch _getRunningOSVersion() {
      case .iOS(let major, _, _):
        return range.contains(major)
      default:
        return false
      }

    case .iOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .iOS(major, minor, _):
        return true
      default:
        return false
      }

    case .iOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .iOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case .iOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .iOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case .iOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .iOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case .iOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .iOSSimulator:
        return true
      default:
        return false
      }

    case .tvOSAny:
      switch _getRunningOSVersion() {
      case .tvOS:
        return true
      default:
        return false
      }

    case .tvOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, _, _):
        return true
      default:
        return false
      }

    case .tvOSMajorRange(let range, _):
      switch _getRunningOSVersion() {
      case .tvOS(let major, _, _):
        return range.contains(major)
      default:
        return false
      }

    case .tvOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, minor, _):
        return true
      default:
        return false
      }

    case .tvOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case .tvOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case .tvOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case .tvOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .tvOSSimulator:
        return true
      default:
        return false
      }

    case .watchOSAny:
      switch _getRunningOSVersion() {
      case .watchOS:
        return true
      default:
        return false
      }

    case .watchOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, _, _):
        return true
      default:
        return false
      }

    case .watchOSMajorRange(let range, _):
      switch _getRunningOSVersion() {
      case .watchOS(let major, _, _):
        return range.contains(major)
      default:
        return false
      }

    case .watchOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, minor, _):
        return true
      default:
        return false
      }

    case .watchOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case .watchOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case .watchOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case .watchOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .watchOSSimulator:
        return true
      default:
        return false
      }

    case .visionOSAny:
      switch _getRunningOSVersion() {
      case .visionOS:
        return true
      default:
        return false
      }

    case .visionOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .visionOS(major, _, _):
        return true
      default:
        return false
      }

    case .visionOSMajorRange(let range, _):
      switch _getRunningOSVersion() {
      case .visionOS(let major, _, _):
        return range.contains(major)
      default:
        return false
      }

    case .visionOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .visionOS(major, minor, _):
        return true
      default:
        return false
      }

    case .visionOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .visionOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case .visionOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .visionOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case .visionOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .visionOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case .visionOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .visionOSSimulator:
        return true
      default:
        return false
      }

    case .linuxAny:
      switch _getRunningOSVersion() {
      case .linux:
        return true
      default:
        return false
      }

    case .androidAny:
      switch _getRunningOSVersion() {
      case .android:
        return true
      default:
        return false
      }

    case .freeBSDAny:
      switch _getRunningOSVersion() {
      case .freeBSD:
        return true
      default:
        return false
      }

    case .ps4Any:
      switch _getRunningOSVersion() {
      case .ps4:
        return true
      default:
        return false
      }

    case .windowsAny:
      switch _getRunningOSVersion() {
      case .windowsCygnus:
        return true
      case .windows:
        return true
      default:
        return false
      }

    case .windowsCygnusAny:
      switch _getRunningOSVersion() {
      case .windowsCygnus:
        return true
      default:
        return false
      }

    case .haikuAny:
      switch _getRunningOSVersion() {
      case .haiku:
        return true
      default:
        return false
      }

    case .wasiAny:
      switch _getRunningOSVersion() {
      case .wasi:
        return true
      default:
        return false
      }

    case .emscriptenAny:
      switch _getRunningOSVersion() {
      case .emscripten:
        return true
      default:
        return false
      }

    case .objCRuntime:
#if _runtime(_ObjC)
      return true
#else
      return false
#endif

    case .nativeRuntime:
#if _runtime(_ObjC)
      return false
#else
      return true
#endif
      
    case .minimumStdlib(let version):
      return !version.isAvailable

    case .missingRequirement(let requirement):
      return requirement.isMissing
    }
  }
}

//
// Semantic tests for protocol conformance
//

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Equatable`, using `oracle` to generate equality
/// expectations from pairs of positions in `instances`.
///
/// - Note: `oracle` is also checked for conformance to the
///   laws.
public func checkEquatable<Instances : Collection>(
  _ instances: Instances,
  oracle: (Instances.Index, Instances.Index) -> Bool,
  allowBrokenTransitivity: Bool = false,

  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Instances.Element : Equatable
{
  let indices = Array(instances.indices)
  _checkEquatableImpl(
    Array(instances),
    oracle: { oracle(indices[$0], indices[$1]) },
    allowBrokenTransitivity: allowBrokenTransitivity,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}

internal func _checkEquatableImpl<Instance : Equatable>(
  _ instances: [Instance],
  oracle: (Int, Int) -> Bool,
  allowBrokenTransitivity: Bool = false,

  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  // For each index (which corresponds to an instance being tested) track the
  // set of equal instances.
  var transitivityScoreboard: [Box<Set<Int>>] =
    instances.indices.map { _ in Box(Set()) }

  // TODO: swift-3-indexing-model: add tests for this function.
  for i in instances.indices {
    let x = instances[i]
    expectTrue(oracle(i, i), "bad oracle: broken reflexivity at index \(i)")

    for j in instances.indices {
      let y = instances[j]

      let predictedXY = oracle(i, j)
      expectEqual(
        predictedXY, oracle(j, i),
        "bad oracle: broken symmetry between indices \(i), \(j)",
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      let isEqualXY = x == y
      expectEqual(
        predictedXY, isEqualXY,
        """
        \((predictedXY
           ? "expected equal, found not equal"
           : "expected not equal, found equal"))
        lhs (at index \(i)): \(String(reflecting: x))
        rhs (at index \(j)): \(String(reflecting: y))
        """,
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      // Not-equal is an inverse of equal.
      expectNotEqual(
        isEqualXY, x != y,
        """
        lhs (at index \(i)): \(String(reflecting: x))
        rhs (at index \(j)): \(String(reflecting: y))
        """,
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      if !allowBrokenTransitivity {
        // Check transitivity of the predicate represented by the oracle.
        // If we are adding the instance `j` into an equivalence set, check that
        // it is equal to every other instance in the set.
        if predictedXY && i < j && transitivityScoreboard[i].value.insert(j).inserted {
          if transitivityScoreboard[i].value.count == 1 {
            transitivityScoreboard[i].value.insert(i)
          }
          for k in transitivityScoreboard[i].value {
            expectTrue(
              oracle(j, k),
              "bad oracle: broken transitivity at indices \(i), \(j), \(k)",
              stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
              // No need to check equality between actual values, we will check
              // them with the checks above.
          }
          precondition(transitivityScoreboard[j].value.isEmpty)
          transitivityScoreboard[j] = transitivityScoreboard[i]
        }
      }
    }
  }
}


public func checkEquatable<T : Equatable>(
  _ expectedEqual: Bool, _ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  checkEquatable(
    [lhs, rhs],
    oracle: { expectedEqual || $0 == $1 }, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line),
    showFrame: false)
}

/// Produce an integer hash value for `value` by feeding it to a dedicated
/// `Hasher`. This is always done by calling the `hash(into:)` method.
/// If a non-nil `seed` is given, it is used to perturb the hasher state;
/// this is useful for resolving accidental hash collisions.
internal func hash<H: Hashable>(_ value: H, seed: Int? = nil) -> Int {
  var hasher = Hasher()
  if let seed = seed {
    hasher.combine(seed)
  }
  hasher.combine(value)
  return hasher.finalize()
}

/// Test that the elements of `groups` consist of instances that satisfy the
/// semantic requirements of `Hashable`, with each group defining a distinct
/// equivalence class under `==`.
public func checkHashableGroups<Groups: Collection>(
  _ groups: Groups,
  _ message: @autoclosure () -> String = "",
  allowIncompleteHashing: Bool = false,
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where Groups.Element: Collection, Groups.Element.Element: Hashable {
  let instances = groups.flatMap { $0 }
  // groupIndices[i] is the index of the element in groups that contains
  // instances[i].
  let groupIndices =
    zip(0..., groups).flatMap { i, group in group.map { _ in i } }
  func equalityOracle(_ lhs: Int, _ rhs: Int) -> Bool {
    return groupIndices[lhs] == groupIndices[rhs]
  }
  checkHashable(
    instances,
    equalityOracle: equalityOracle,
    hashEqualityOracle: equalityOracle,
    allowBrokenTransitivity: false,
    allowIncompleteHashing: allowIncompleteHashing,
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line),
    showFrame: false)
}

/// Test that the elements of `instances` satisfy the semantic requirements of
/// `Hashable`, using `equalityOracle` to generate equality and hashing
/// expectations from pairs of positions in `instances`.
public func checkHashable<Instances: Collection>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  allowBrokenTransitivity: Bool = false,
  allowIncompleteHashing: Bool = false,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where Instances.Element: Hashable {
  checkHashable(
    instances,
    equalityOracle: equalityOracle,
    hashEqualityOracle: equalityOracle,
    allowBrokenTransitivity: allowBrokenTransitivity,
    allowIncompleteHashing: allowIncompleteHashing,
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line),
    showFrame: false)
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Hashable`, using `equalityOracle` to generate
/// equality expectations from pairs of positions in `instances`,
/// and `hashEqualityOracle` to do the same for hashing.
public func checkHashable<Instances: Collection>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  hashEqualityOracle: (Instances.Index, Instances.Index) -> Bool,
  allowBrokenTransitivity: Bool = false,
  allowIncompleteHashing: Bool = false,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Instances.Element: Hashable {
  checkEquatable(
    instances,
    oracle: equalityOracle,
    allowBrokenTransitivity: allowBrokenTransitivity,
    message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

  for i in instances.indices {
    let x = instances[i]
    for j in instances.indices {
      let y = instances[j]
      let predicted = hashEqualityOracle(i, j)
      expectEqual(
        predicted, hashEqualityOracle(j, i),
        "bad hash oracle: broken symmetry between indices \(i), \(j)",
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
      if x == y {
        expectTrue(
          predicted,
          """
          bad hash oracle: equality must imply hash equality
          lhs (at index \(i)): \(x)
          rhs (at index \(j)): \(y)
          """,
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
      }
      if predicted {
        expectEqual(
          hash(x), hash(y),
          """
          hash(into:) expected to match, found to differ
          lhs (at index \(i)): \(x)
          rhs (at index \(j)): \(y)
          """,
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
        expectEqual(
          x.hashValue, y.hashValue,
          """
          hashValue expected to match, found to differ
          lhs (at index \(i)): \(x)
          rhs (at index \(j)): \(y)
          """,
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
        expectEqual(
          x._rawHashValue(seed: 0), y._rawHashValue(seed: 0),
          """
          _rawHashValue(seed:) expected to match, found to differ
          lhs (at index \(i)): \(x)
          rhs (at index \(j)): \(y)
          """,
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
      } else if !allowIncompleteHashing {
        // Try a few different seeds; at least one of them should discriminate
        // between the hashes. It is extremely unlikely this check will fail
        // all ten attempts, unless the type's hash encoding is not unique,
        // or unless the hash equality oracle is wrong.
        expectTrue(
          (0..<10).contains { hash(x, seed: $0) != hash(y, seed: $0) },
          """
          hash(into:) expected to differ, found to match
          lhs (at index \(i)): \(x)
          rhs (at index \(j)): \(y)
          """,
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
        expectTrue(
          (0..<10).contains { i in
            x._rawHashValue(seed: i) != y._rawHashValue(seed: i)
          },
          """
          _rawHashValue(seed:) expected to differ, found to match
          lhs (at index \(i)): \(x)
          rhs (at index \(j)): \(y)
          """,
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
      }
    }
  }
}

public func checkHashable<T : Hashable>(
  expectedEqual: Bool, _ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  checkHashable(
    [lhs, rhs], equalityOracle: { expectedEqual || $0 == $1 }, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}

public enum ExpectedComparisonResult {
  case lt, eq, gt

  public func isLT() -> Bool {
    return self == .lt
  }

  public func isEQ() -> Bool {
    return self == .eq
  }

  public func isGT() -> Bool {
    return self == .gt
  }

  public func isLE() -> Bool {
    return isLT() || isEQ()
  }

  public func isGE() -> Bool {
    return isGT() || isEQ()
  }

  public func isNE() -> Bool {
    return !isEQ()
  }

  public func flip() -> ExpectedComparisonResult {
    switch self {
    case .lt:
      return .gt
    case .eq:
      return .eq
    case .gt:
      return .lt
    }
  }
}

extension ExpectedComparisonResult : CustomStringConvertible {
  public var description: String {
    switch self {
    case .lt:
      return "<"
    case .eq:
      return "=="
    case .gt:
      return ">"
    }
  }
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Comparable`, using `oracle` to generate comparison
/// expectations from pairs of positions in `instances`.
///
/// - Note: `oracle` is also checked for conformance to the
///   laws.
public func checkComparable<Instances : Collection>(
  _ instances: Instances,
  oracle: (Instances.Index, Instances.Index) -> ExpectedComparisonResult,

  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Instances.Element : Comparable {

  // Also checks that equality is consistent with comparison and that
  // the oracle obeys the equality laws
  checkEquatable(instances, oracle: { oracle($0, $1).isEQ() }, message(),
    stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

  for i in instances.indices {
    let x = instances[i]

    expectFalse(
      x < x,
      "found 'x < x'\n" +
      "at index \(i): \(String(reflecting: x))",
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

    expectFalse(
      x > x,
      "found 'x > x'\n" +
      "at index \(i): \(String(reflecting: x))",
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

    expectTrue(x <= x,
      "found 'x <= x' to be false\n" +
      "at index \(i): \(String(reflecting: x))",
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

    expectTrue(x >= x,
      "found 'x >= x' to be false\n" +
      "at index \(i): \(String(reflecting: x))",
        stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

    for j in instances.indices where i != j {
      let y = instances[j]

      let expected = oracle(i, j)

      expectEqual(
        expected.flip(), oracle(j, i),
        "bad oracle: missing antisymmetry: "
        + "(\(String(reflecting: i)), \(String(reflecting: j)))",
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      expectEqual(expected.isLT(), x < y,
        "x < y\n" +
        "lhs (at index \(i)): \(String(reflecting: x))\n" +
        "rhs (at index \(j)): \(String(reflecting: y))",
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      expectEqual(expected.isLE(), x <= y,
        "x <= y\n" +
        "lhs (at index \(i)): \(String(reflecting: x))\n" +
        "rhs (at index \(j)): \(String(reflecting: y))",
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      expectEqual(expected.isGE(), x >= y,
        "x >= y\n" +
        "lhs (at index \(i)): \(String(reflecting: x))\n" +
        "rhs (at index \(j)): \(String(reflecting: y))",
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      expectEqual(expected.isGT(), x > y,
        "x > y\n" +
        "lhs (at index \(i)): \(String(reflecting: x))\n" +
        "rhs (at index \(j)): \(String(reflecting: y))",
          stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

      for k in instances.indices {
        let expected2 = oracle(j, k)
        if expected == expected2 {
          expectEqual(
            expected, oracle(i, k),
            "bad oracle: missing transitivity "
            + "(\(String(reflecting: i)), \(String(reflecting: j)), "
            + "\(String(reflecting: k)))", stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
        }
      }
    }
  }
}

public func checkComparable<T : Comparable>(
  _ expected: ExpectedComparisonResult, _ lhs: T, _ rhs: T,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  checkComparable(
    [lhs, rhs],
    oracle: { [[ .eq, expected], [ expected.flip(), .eq]][$0][$1] },
    message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}


/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Strideable`, using `advanceOracle` and
/// 'distanceOracle' to generate expectations about the results of
/// `advanced(by:)` and `distance(to:)` from pairs of positions in
/// `instances` and `strides`.
///
/// - Note: `oracle` is also checked for conformance to the
///   laws.
public func checkStrideable<Instances : Collection, Strides : Collection>(
  _ instances: Instances, strides: Strides,
  distanceOracle:
    (Instances.Index, Instances.Index) -> Strides.Element,
  advanceOracle:
    (Instances.Index, Strides.Index) -> Instances.Element,

  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Instances.Element : Strideable,
  Instances.Element.Stride == Strides.Element {

  checkComparable(
    instances,
    oracle: {
      let d = distanceOracle($1, $0);
      return d < 0 ? .lt : d == 0 ? .eq : .gt
    },
    message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))

  for i in instances.indices {
    let x = instances[i]
    expectEqual(x, x.advanced(by: 0))

    for j in strides.indices {
      let y = strides[j]
      expectEqual(advanceOracle(i, j), x.advanced(by: y))
    }

    for j in instances.indices {
      let y = instances[j]
      expectEqual(distanceOracle(i, j), x.distance(to: y))
    }
  }
}

public func checkLosslessStringConvertible<Instance>(
  _ instances: [Instance]
) where Instance : LosslessStringConvertible & Equatable {
  expectEqualFunctionsForDomain(instances, { $0 }, { Instance(String($0))! })
}

public func nthIndex<C: Collection>(_ x: C, _ n: Int) -> C.Index {
  return x.index(x.startIndex, offsetBy: n)
}

public func nth<C: Collection>(_ x: C, _ n: Int) -> C.Element {
  return x[nthIndex(x, n)]
}

public func expectEqualSequence<
  Expected: Sequence,
  Actual: Sequence
>(
  _ expected: Expected, _ actual: Actual,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Expected.Element == Actual.Element,
  Expected.Element : Equatable {

  expectEqualSequence(expected, actual, message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) { $0 == $1 }
}

public func expectEqualSequence<
  Expected : Sequence,
  Actual : Sequence,
  T : Equatable,
  U : Equatable
>(
  _ expected: Expected, _ actual: Actual,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Expected.Element == Actual.Element,
  Expected.Element == (T, U) {

  expectEqualSequence(
    expected, actual, message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) {
    (lhs: (T, U), rhs: (T, U)) -> Bool in
    lhs.0 == rhs.0 && lhs.1 == rhs.1
  }
}

public func expectEqualSequence<
  Expected: Sequence,
  Actual: Sequence
>(
  _ expected: Expected, _ actual: Actual,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line,
  sameValue: (Expected.Element, Expected.Element) -> Bool
) where
  Expected.Element == Actual.Element {

  if !expected.elementsEqual(actual, by: sameValue) {
    expectationFailure("expected elements: \"\(expected)\"\n"
      + "actual: \"\(actual)\" (of type \(String(reflecting: type(of: actual))))",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}

public func expectEqualsUnordered<
  Expected : Sequence,
  Actual : Sequence
>(
  _ expected: Expected, _ actual: Actual,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line,
  compare: @escaping (Expected.Element, Expected.Element)
    -> ExpectedComparisonResult
) where
  Expected.Element == Actual.Element {

  let x: [Expected.Element] =
    expected.sorted { compare($0, $1).isLT() }
  let y: [Actual.Element] =
    actual.sorted { compare($0, $1).isLT() }
  expectEqualSequence(
    x, y, message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), sameValue: { compare($0, $1).isEQ() })
}

public func expectEqualsUnordered<
  Expected : Sequence,
  Actual : Sequence
>(
  _ expected: Expected, _ actual: Actual,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Expected.Element == Actual.Element,
  Expected.Element : Comparable {

  expectEqualsUnordered(expected, actual, message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line)) {
    $0 < $1 ? .lt : $0 == $1 ? .eq : .gt
  }
}

public func expectEqualsUnordered<T : Comparable>(
  _ expected: [T], _ actual: [T],
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) {
  let x = expected.sorted()
  let y = actual.sorted()
  expectEqualSequence(x, y, message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
}

public func expectEqualsUnordered<T : Strideable>(
  _ expected: Range<T>, _ actual: [T],
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where T.Stride: SignedInteger {
  if expected.count != actual.count {
    expectationFailure("expected elements: \"\(expected)\"\n"
      + "actual: \"\(actual)\" (of type \(String(reflecting: type(of: actual))))",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
  for e in actual {
    if !expected.contains(e) {
      expectationFailure("expected elements: \"\(expected)\"\n"
        + "actual: \"\(actual)\" (of type \(String(reflecting: type(of: actual))))",
        trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
    }
  }
}

/// A nominal type that is equivalent to a tuple of two elements.
///
/// We need a nominal type because we can't add protocol conformances to
/// tuples.
struct Pair<T : Comparable> : Comparable {
  init(_ first: T, _ second: T) {
    self.first = first
    self.second = second
  }

  var first: T
  var second: T

  static func ==(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
    return lhs.first == rhs.first && lhs.second == rhs.second
  }

  static func <(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
    return [lhs.first, lhs.second].lexicographicallyPrecedes(
      [rhs.first, rhs.second])
  }
}

public func expectEqualsUnordered<
  Expected : Sequence,
  Actual : Sequence,
  T : Comparable
>(
  _ expected: Expected, _ actual: Actual,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line
) where
  Actual.Element == (key: T, value: T),
  Expected.Element == (T, T) {

  func comparePairLess(_ lhs: (T, T), rhs: (T, T)) -> Bool {
    return [lhs.0, lhs.1].lexicographicallyPrecedes([rhs.0, rhs.1])
  }

  let x: [(T, T)] =
    expected.sorted(by: comparePairLess)
  let y: [(T, T)] =
    actual.map { ($0.0, $0.1) }
      .sorted(by: comparePairLess)

  func comparePairEquals(_ lhs: (T, T), rhs: (key: T, value: T)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1
  }

  expectEqualSequence(x, y, message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line), sameValue: comparePairEquals)
}

public func expectEqualFunctionsForDomain<ArgumentType, Result : Equatable>(
    _ arguments: [ArgumentType], _ function1: (ArgumentType) -> Result,
    _ function2: (ArgumentType) -> Result
) {
  for a in arguments {
    let expected = function1(a)
    let actual = function2(a)
    expectEqual(expected, actual, "where the argument is: \(a)")
  }
}

public func expectEqualMethodsForDomain<
  SelfType, ArgumentType, Result : Equatable
>(
  _ selfs: [SelfType], _ arguments: [ArgumentType],
  _ function1: (SelfType) -> (ArgumentType) -> Result,
  _ function2: (SelfType) -> (ArgumentType) -> Result
) {
  for s in selfs {
    for a in arguments {
      let expected = function1(s)(a)
      let actual = function2(s)(a)
      expectEqual(
        expected, actual,
        "where the first argument is: \(s)\nand the second argument is: \(a)"
      )
    }
  }
}

public func expectEqualUnicodeScalars<S: StringProtocol>(
  _ expected: [UInt32], _ actual: S,
  _ message: @autoclosure () -> String = "",
  stackTrace: SourceLocStack = SourceLocStack(),
  showFrame: Bool = true,
  file: String = #file, line: UInt = #line) {
  let actualUnicodeScalars = Array(
    actual.unicodeScalars.lazy.map { $0.value })

  if !expected.elementsEqual(actualUnicodeScalars) {
    expectationFailure(
      "expected elements: \"\(asHex(expected))\"\n"
      + "actual: \"\(asHex(actualUnicodeScalars))\"",
      trace: message(),
      stackTrace: stackTrace.pushIf(showFrame, file: file, line: line))
  }
}
