Files
swift-mirror/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
Jordan Rose bc83940301 Make pointer nullability explicit using Optional.
Implements SE-0055: https://github.com/apple/swift-evolution/blob/master/proposals/0055-optional-unsafe-pointers.md

- Add NULL as an extra inhabitant of Builtin.RawPointer (currently
  hardcoded to 0 rather than being target-dependent).
- Import non-object pointers as Optional/IUO when nullable/null_unspecified
  (like everything else).
- Change the type checker's *-to-pointer conversions to handle a layer of
  optional.
- Use 'AutoreleasingUnsafeMutablePointer<NSError?>?' as the type of error
  parameters exported to Objective-C.
- Drop NilLiteralConvertible conformance for all pointer types.
- Update the standard library and then all the tests.

I've decided to leave this commit only updating existing tests; any new
tests will come in the following commits. (That may mean some additional
implementation work to follow.)

The other major piece that's missing here is migration. I'm hoping we get
a lot of that with Swift 1.1's work for optional object references, but
I still need to investigate.
2016-04-11 20:06:38 -07:00

2883 lines
81 KiB
Swift

//===--- StdlibUnittest.swift.gyb -----------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import SwiftPrivate
import SwiftPrivatePthreadExtras
import SwiftPrivateLibcExtras
#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
import Darwin
#elseif os(Linux) || os(FreeBSD)
import Glibc
#endif
#if _runtime(_ObjC)
import ObjectiveC
#endif
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())))
}
}
%{
TRACE = '''@autoclosure _ message: () -> String = "",
showFrame: Bool = true,
stackTrace: SourceLocStack = SourceLocStack(),
file: String = #file, line: UInt = #line'''
stackTrace = 'stackTrace.pushIf(showFrame, file: file, line: line)'
trace = 'message(),\n stackTrace: ' + stackTrace
}%
func _printStackTrace(_ stackTrace: SourceLocStack?) {
guard let s = stackTrace where !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)")
}
}
// FIXME: these variables should be atomic, since multiple threads can call
// `expect*()` functions.
var _anyExpectFailed = false
var _seenExpectCrash = false
/// Run `body` and expect a failure to happen.
///
/// The check passes iff `body` triggers one or more failures.
public func expectFailure(${TRACE}, body: () -> Void) {
let startAnyExpectFailed = _anyExpectFailed
_anyExpectFailed = false
body()
let endAnyExpectFailed = _anyExpectFailed
_anyExpectFailed = false
expectTrue(
endAnyExpectFailed, "running `body` should produce an expected failure",
stackTrace: ${stackTrace}
)
_anyExpectFailed = _anyExpectFailed || startAnyExpectFailed
}
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>(_ expected: T, _ actual: T, ${TRACE}) {
expectEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1}
}
public func expectEqual<T : Equatable, U : Equatable>(
_ expected: (T, U), _ actual: (T, U), ${TRACE}) {
expectEqual(expected.0, actual.0, ${trace}, showFrame: false) {$0 == $1}
expectEqual(expected.1, actual.1, ${trace}, showFrame: false) {$0 == $1}
}
public func expectationFailure(
_ reason: String,
trace message: String,
stackTrace: SourceLocStack) {
_anyExpectFailed = true
stackTrace.print()
print(reason, terminator: reason == "" ? "" : "\n")
print(message, terminator: message == "" ? "" : "\n")
}
public func expectEqual<T>(
_ expected: T, _ actual: T, ${TRACE}, sameValue equal: (T,T) -> Bool
) {
if !equal(expected, actual) {
expectationFailure(
"expected: \(String(reflecting: expected)) (of type \(String(reflecting: expected.dynamicType)))\n"
+ "actual: \(String(reflecting: actual)) (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace}
)
}
}
public func expectNotEqual<T : Equatable>(_ expected: T, _ actual: T, ${TRACE}) {
if expected == actual {
expectationFailure(
"unexpected value: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace}
)
}
}
// Cannot write a sane set of overloads using generics because of:
// <rdar://problem/17015923> Array->NSArray implicit conversion insanity
public func expectOptionalEqual<T : Equatable>(
_ expected: T, _ actual: T?, ${TRACE}
) {
expectOptionalEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1}
}
public func expectOptionalEqual<T>(
_ expected: T, _ actual: T?, ${TRACE}, sameValue equal: (T,T) -> Bool
) {
if (actual == nil) || !equal(expected, actual!) {
expectationFailure(
"expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
public func expectEqual<T : Equatable>(_ expected: T?, _ actual: T?, ${TRACE}) {
if expected != actual {
expectationFailure(
"expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
public func expectNotEqual<T : Equatable>(
_ expected: T?, _ actual: T?, ${TRACE}
) {
if expected == actual {
expectationFailure(
"unexpected value: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
// Array<T> is not Equatable if T is. Provide additional overloads.
// Same for Dictionary.
%for (Generic, EquatableType) in [
% ('<T : Equatable>', 'ContiguousArray<T>'),
% ('<T : Equatable>', 'ArraySlice<T>'),
% ('<T : Equatable>', 'Array<T>'),
% ('<T, U : Equatable>', 'Dictionary<T, U>')]:
public func expectEqual${Generic}(
_ expected: ${EquatableType}, _ actual: ${EquatableType}, ${TRACE}
) {
expectEqual(expected, actual, ${trace}, showFrame: false) { $0 == $1 }
}
public func expectOptionalEqual${Generic}(
_ expected: ${EquatableType}, _ actual: ${EquatableType}?, ${TRACE}) {
if (actual == nil) || expected != actual! {
expectationFailure(
"expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
%end
public func expectLT(_ lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs < rhs) {
expectationFailure("\(lhs) < \(rhs)", trace: ${trace})
}
}
public func expectLE(_ lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs <= rhs) {
expectationFailure("\(lhs) <= \(rhs)", trace: ${trace})
}
}
public func expectGT(_ lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs > rhs) {
expectationFailure("\(lhs) > \(rhs)", trace: ${trace})
}
}
public func expectGE(_ lhs: Int, _ rhs: Int, ${TRACE}) {
if !(lhs >= rhs) {
expectationFailure("\(lhs) >= \(rhs)", trace: ${trace})
}
}
public func expectType<T>(_: T.Type, _ x: inout T) {}
public func expectEqualType<T>(_: T.Type, _: T.Type) {}
public func expectSequenceType<
X : Sequence
where
X.SubSequence : Sequence,
X.SubSequence.Iterator.Element == X.Iterator.Element,
X.SubSequence.SubSequence == X.SubSequence
>(_ x: X) -> X { return x }
public func expectIndexable<X : Indexable>(_ x: X) -> X { return x }
public func expectCollectionType<
X : Collection
where
X.SubSequence : Collection,
X.SubSequence.Iterator.Element == X.Iterator.Element,
X.SubSequence.SubSequence == X.SubSequence
>(_ x: X) -> X { return x }
/// A slice is a `Collection` that when sliced returns an instance of
/// itself.
public func expectSliceType<
X : Collection
where
X.SubSequence == X
>(_ sliceType: X.Type) {}
/// A mutable slice is a `MutableCollection` that when sliced returns an
/// instance of itself.
public func expectMutableSliceType<
X : MutableCollection
where
X.SubSequence == X
>(_ mutableSliceType: X.Type) {}
/// Check all associated types of a `Collection`.
public func expectCollectionAssociatedTypes<
X : Collection,
Iterator : IteratorProtocol,
SubSequence : Sequence,
Index : ForwardIndex
where
X.Index == Index
>(
collectionType: X.Type,
iteratorType: Iterator.Type,
subSequenceType: SubSequence.Type,
indexType: Index.Type
) {}
public func expectForwardIndexType<X : ForwardIndex>(_ x: X) -> X { return x }
public func expectIsBooleanType<X : Boolean>(_ x: inout X) -> X { return x }
public struct AssertionResult : CustomStringConvertible, Boolean {
init(isPass: Bool) {
self._isPass = isPass
}
public var boolValue: Bool {
return _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(${TRACE}) {
expectationFailure("this code should not be executed", trace: ${trace})
}
public func expectUnreachableCatch(_ error: ErrorProtocol, ${TRACE}) {
expectationFailure(
"error should not be thrown: \"\(error)\"", trace: ${trace})
}
%for BoolType in ['Bool', 'AssertionResult']:
public func expectTrue(_ actual: ${BoolType}, ${TRACE}) {
if !actual {
expectationFailure("expected: true", trace: ${trace})
}
}
public func expectFalse(_ actual: ${BoolType}, ${TRACE}) {
if actual {
expectationFailure("expected: false", trace: ${trace})
}
}
%end
public func expectEmpty<T>(_ value: T?, ${TRACE}) {
if value != nil {
expectationFailure(
"expected optional to be empty\nactual: \"\(value)\"", trace: ${trace})
}
}
public func expectNotEmpty<T>(_ value: T?, ${TRACE}) -> T? {
if value == nil {
expectationFailure("expected optional to be non-empty", trace: ${trace})
}
return value
}
public func expectCrashLater() {
print("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed)")
var stderr = _Stderr()
print("\(_stdlibUnittestStreamPrefix);expectCrash", to: &stderr)
_seenExpectCrash = true
}
func _defaultTestSuiteFailedCallback() {
abort()
}
var _testSuiteFailedCallback: () -> Void = _defaultTestSuiteFailedCallback
public func _setTestSuiteFailedCallback(_ callback: () -> Void) {
_testSuiteFailedCallback = callback
}
extension ProcessTerminationStatus {
var isSwiftTrap: Bool {
switch self {
case .exit(_):
return false
case .signal(let signal):
return CInt(signal) == SIGILL || CInt(signal) == SIGTRAP
default:
fatalError("Bad ProcessTerminationStatus")
}
}
}
func _stdlib_getline() -> String? {
var result: [UInt8] = []
while true {
let c = getchar()
if c == EOF {
if result.isEmpty {
return nil
}
return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result)
}
if c == CInt(UnicodeScalar("\n").value) {
return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result)
}
result.append(UInt8(c))
}
}
func _printDebuggingAdvice(_ fullTestName: String) {
print("To debug, run:")
var invocation = [Process.arguments[0]]
let interpreter = getenv("SWIFT_INTERPRETER")
if interpreter != nil {
if let interpreterCmd = String(validatingUTF8: interpreter) {
invocation.insert(interpreterCmd, at: 0)
}
}
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("swift_stdlib_installTrapInterceptor")
func _stdlib_installTrapInterceptor()
#if _runtime(_ObjC)
@objc protocol _StdlibUnittestNSException {
optional var name: AnyObject { get }
}
#endif
func _childProcess() {
_stdlib_installTrapInterceptor()
#if _runtime(_ObjC)
objc_setUncaughtExceptionHandler {
var stderr = _Stderr()
let maybeNSException = unsafeBitCast($0, to:_StdlibUnittestNSException.self)
if let name = maybeNSException.name {
print("*** [StdlibUnittest] Terminating due to uncaught exception " +
"\(name): \($0)",
to: &stderr)
} else {
print("*** [StdlibUnittest] Terminating due to uncaught exception: \($0)",
to: &stderr)
}
}
#endif
while let line = _stdlib_getline() {
let parts = line._split(separator: ";")
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 = false
testSuite._runTest(name: testName, parameter: testParameter)
print("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed)")
var stderr = _Stderr()
print("\(_stdlibUnittestStreamPrefix);end", to: &stderr)
if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
return
}
}
}
struct _ParentProcess {
internal var _pid: pid_t = -1
internal var _childStdin: _FDOutputStream = _FDOutputStream(fd: -1)
internal var _childStdout: _FDInputStream = _FDInputStream(fd: -1)
internal var _childStderr: _FDInputStream = _FDInputStream(fd: -1)
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
}
mutating func _spawnChild() {
let params = [ "--stdlib-unittest-run-child" ] + _args
let (pid, childStdinFD, childStdoutFD, childStderrFD) = spawnChild(params)
_pid = pid
_childStdin = _FDOutputStream(fd: childStdinFD)
_childStdout = _FDInputStream(fd: childStdoutFD)
_childStderr = _FDInputStream(fd: childStderrFD)
}
mutating func _waitForChild() -> ProcessTerminationStatus {
let status = posixWaitpid(_pid)
_pid = -1
_childStdin.close()
_childStdout.close()
_childStderr.close()
_childStdin = _FDOutputStream(fd: -1)
_childStdout = _FDInputStream(fd: -1)
_childStderr = _FDInputStream(fd: -1)
return status
}
/// Returns the values of the corresponding variables in the child process.
internal mutating func _runTestInChild(
_ testSuite: TestSuite,
_ testName: String,
parameter: Int?
) -> (anyExpectFailed: Bool, seenExpectCrash: Bool,
status: ProcessTerminationStatus?,
crashStdout: [String], crashStderr: [String]) {
if _pid <= 0 {
_spawnChild()
}
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 readfds = _stdlib_fd_set()
var writefds = _stdlib_fd_set()
var errorfds = _stdlib_fd_set()
var stdoutSeenCrashDelimiter = false
var stderrSeenCrashDelimiter = false
var stdoutEnd = false
var stderrEnd = false
var capturedCrashStdout: [String] = []
var capturedCrashStderr: [String] = []
var anyExpectFailedInChild = false
while !((_childStdout.isEOF && _childStderr.isEOF) ||
(stdoutEnd && stderrEnd)) {
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 var line = _childStdout.getline() {
if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage =
line[index..<line.endIndex]._split(separator: ";")
switch controlMessage[1] {
case "expectCrash":
stdoutSeenCrashDelimiter = true
anyExpectFailedInChild = controlMessage[2] == "true"
case "end":
stdoutEnd = true
anyExpectFailedInChild = controlMessage[2] == "true"
default:
fatalError("unexpected message")
}
line = line[line.startIndex..<index]
if line.isEmpty {
continue
}
}
if stdoutSeenCrashDelimiter {
capturedCrashStdout.append(line)
}
print("stdout>>> \(line)")
}
continue
}
if readfds.isset(_childStderr.fd) || errorfds.isset(_childStderr.fd) {
_childStderr.read()
while var line = _childStderr.getline() {
if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage =
line[index..<line.endIndex]._split(separator: ";")
switch controlMessage[1] {
case "expectCrash":
stderrSeenCrashDelimiter = true
case "end":
stderrEnd = true
default:
fatalError("unexpected message")
}
line = line[line.startIndex..<index]
if line.isEmpty {
continue
}
}
if stderrSeenCrashDelimiter {
capturedCrashStderr.append(line)
if findSubstring(line, _crashedPrefix) != nil {
line = "OK: saw expected \"\(line.lowercased())\""
}
}
print("stderr>>> \(line)")
}
continue
}
}
// Check if the child has sent us "end" markers for the current test.
if stdoutEnd && stderrEnd {
testSuite._testByName(testName)
var status: ProcessTerminationStatus? = nil
if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
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 enum _TestStatus {
case skip([TestRunPredicate])
case pass
case fail
case uxPass
case xFail
}
internal mutating 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? = nil
var crashStdout: [String] = []
var crashStderr: [String] = []
if _runTestsInProcess {
if t.stdinText != nil {
print("The test \(fullTestName) requires stdin input and can't be run in-process, marking as failed")
_anyExpectFailed = true
} else {
_anyExpectFailed = false
testSuite._runTest(name: t.name, parameter: testParameter)
}
} else {
(_anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
crashStderr) =
_runTestInChild(testSuite, t.name, parameter: testParameter)
}
// Determine if the test passed, not taking XFAILs into account.
var testPassed = false
switch (childTerminationStatus, expectCrash) {
case (.none, false):
testPassed = !_anyExpectFailed
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
}
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
}
}
mutating 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
where 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")
}
}
}
}
// 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 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 =
Process.arguments.contains("--stdlib-unittest-run-child")
if _isChildProcess {
_childProcess()
} else {
var runTestsInProcess: Bool = false
var filter: String? = nil
var args = [String]()
var i = 0
i += 1 // Skip the name of the executable.
while i < Process.arguments.count {
let arg = Process.arguments[i]
if arg == "--stdlib-unittest-in-process" {
runTestsInProcess = true
i += 1
continue
}
if arg == "--stdlib-unittest-filter" {
filter = Process.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(Process.arguments[i])
i += 1
}
var parent = _ParentProcess(
runTestsInProcess: runTestsInProcess, args: args, filter: filter)
parent.run()
}
}
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()
}
public func test(
_ name: String,
file: String = #file, line: UInt = #line,
_ testFunction: () -> Void
) {
_TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
.code(testFunction)
}
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: () -> Void) {
_precondition(_testSetUpCode == nil, "set-up code already set")
_testSetUpCode = code
}
public func tearDown(_ code: () -> 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)
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 let f = _testTearDownCode {
f()
}
expectEqual(
0, LifetimeTracked.instances, "leaked LifetimeTracked instances:",
file: test.testLoc.file, line: test.testLoc.line)
}
func _testByName(_ testName: String) -> _Test {
return _tests[_testNameToIndex[testName]!]
}
internal enum _TestCode {
case single(code: () -> Void)
case parameterized(code: (Int) -> Void, count: Int)
}
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
/// 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 (0..<count).map { $0 }
}
}
}
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? = nil
var _stdinEndsWithEOF: Bool = false
var _crashOutputMatches: [String] = []
var _testLoc: SourceLoc? = nil
}
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 stdin(_ stdinText: String, eof: Bool = false) -> _TestBuilder {
_data._stdinText = stdinText
_data._stdinEndsWithEOF = eof
return self
}
public func crashOutputMatches(_ string: String) -> _TestBuilder {
_data._crashOutputMatches.append(string)
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))
_testSuite._testNameToIndex[_name] = _testSuite._tests.count - 1
}
public func code(_ testFunction: () -> Void) {
_build(.single(code: testFunction))
}
public func forEach<Data>(
in parameterSets: [Data],
testFunction: (Data) -> Void
) {
_build(.parameterized(
code: { (i: Int) in testFunction(parameterSets[i]) },
count: parameterSets.count))
}
}
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 os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
@_silgen_name("swift_stdlib_getSystemVersionPlistProperty")
func _stdlib_getSystemVersionPlistPropertyImpl(
_ propertyName: UnsafePointer<CChar>) -> UnsafePointer<CChar>?
func _stdlib_getSystemVersionPlistProperty(_ propertyName: String) -> String? {
let cs = _stdlib_getSystemVersionPlistPropertyImpl(propertyName)
return cs.map(String.init(cString:))
}
#endif
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 iOSSimulator
case tvOSSimulator
case watchOSSimulator
case linux
case freeBSD
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 iOSSimulator:
return "iOSSimulator"
case tvOSSimulator:
return "TVOSSimulator"
case watchOSSimulator:
return "watchOSSimulator"
case linux:
return "Linux"
case freeBSD:
return "FreeBSD"
}
}
}
func _parseDottedVersion(_ s: String) -> [Int] {
return Array(s._split(separator: ".").lazy.map { Int($0)! })
}
public func _parseDottedVersionTriple(_ s: String) -> (Int, Int, Int) {
var 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) && (arch(i386) || arch(x86_64))
// 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) && (arch(i386) || arch(x86_64))
return .tvOSSimulator
#elseif os(watchOS) && (arch(i386) || arch(x86_64))
return .watchOSSimulator
#elseif os(Linux)
return .linux
#elseif os(FreeBSD)
return .freeBSD
#else
let productVersion = _stdlib_getSystemVersionPlistProperty("ProductVersion")!
let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion)
#if os(OSX)
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)
#else
fatalError("could not determine OS version")
#endif
#endif
}
var _runningOSVersion: OSVersion = _getOSVersion()
var _overrideOSVersion: OSVersion? = nil
/// 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, Range<Int>, reason: String)
case osxBugFix(Int, Int, Int, reason: String)
case osxBugFixRange(Int, Int, Range<Int>, reason: String)
case iOSAny(/*reason:*/ String)
case iOSMajor(Int, reason: String)
case iOSMinor(Int, Int, reason: String)
case iOSMinorRange(Int, Range<Int>, reason: String)
case iOSBugFix(Int, Int, Int, reason: String)
case iOSBugFixRange(Int, Int, Range<Int>, reason: String)
case iOSSimulatorAny(/*reason:*/ String)
case tvOSAny(/*reason:*/ String)
case tvOSMajor(Int, reason: String)
case tvOSMinor(Int, Int, reason: String)
case tvOSMinorRange(Int, Range<Int>, reason: String)
case tvOSBugFix(Int, Int, Int, reason: String)
case tvOSBugFixRange(Int, Int, Range<Int>, reason: String)
case tvOSSimulatorAny(/*reason:*/ String)
case watchOSAny(/*reason:*/ String)
case watchOSMajor(Int, reason: String)
case watchOSMinor(Int, Int, reason: String)
case watchOSMinorRange(Int, Range<Int>, reason: String)
case watchOSBugFix(Int, Int, Int, reason: String)
case watchOSBugFixRange(Int, Int, Range<Int>, reason: String)
case watchOSSimulatorAny(/*reason:*/ String)
case linuxAny(reason: String)
case freeBSDAny(reason: String)
case objCRuntime(/*reason:*/ String)
case nativeRuntime(/*reason:*/ String)
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 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 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 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 linuxAny(reason: let reason):
return "linuxAny(*, reason: \(reason))"
case freeBSDAny(reason: let reason):
return "freeBSDAny(*, reason: \(reason))"
case objCRuntime(let reason):
return "Objective-C runtime, reason: \(reason))"
case nativeRuntime(let reason):
return "Native runtime (no ObjC), reason: \(reason))"
}
}
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 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 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 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 linuxAny:
switch _getRunningOSVersion() {
case .linux:
return true
default:
return false
}
case freeBSDAny:
switch _getRunningOSVersion() {
case .freeBSD:
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
}
}
}
//
// 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 where Instances.Iterator.Element : Equatable
>(
_ instances: Instances,
oracle: (Instances.Index, Instances.Index) -> Bool,
${TRACE}
) {
for i in instances.indices {
expectTrue(oracle(i, i), "bad oracle: broken reflexivity at index \(i)")
let x = instances[i]
// Reflexivity
expectEqual(x, x, ${trace})
for j in instances.indices {
let predictedXY = oracle(i, j)
expectEqual(
predictedXY, oracle(j, i),
"bad oracle: broken symmetry between indices \(i), \(j)")
let y = instances[j]
let xy = x == y
expectEqual(predictedXY, xy, ${trace})
// Not-equal is an inverse of equal
expectNotEqual(xy, x != y, ${trace})
// Symmetry
expectEqual(xy, y == x, ${trace})
for k in instances.indices {
let z = instances[k]
// Transitivity
if xy && y == z {
expectTrue(
oracle(i, k),
"bad oracle: broken transitivity at indices \(i), \(j), \(k)")
expectEqual(x, z, ${trace})
}
}
}
}
}
public func checkEquatable<T : Equatable>(
_ expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
) {
checkEquatable(
[lhs, rhs],
oracle: { expectedEqual || $0 == $1 }, ${trace}, 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`.
public func checkHashable<
Instances: Collection where Instances.Iterator.Element : Hashable
>(
_ instances: Instances,
equalityOracle: (Instances.Index, Instances.Index) -> Bool,
${TRACE}
) {
checkEquatable(instances, oracle: equalityOracle, ${trace})
for x in instances {
for y in instances {
if x == y {
expectEqual(x.hashValue, y.hashValue, ${trace})
}
}
}
}
public func checkHashable<T : Hashable>(
_ expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
) {
checkHashable(
[lhs, rhs], equalityOracle: { expectedEqual || $0 == $1 }, ${trace})
}
% for inc, protocol, successor, end in (
% ('inc', '_Incrementable', 'successor', 'end'),
% ('dec', 'BidirectionalIndex', 'predecessor', 'start')):
/// Test that the elements of `instances` satisfy
/// ${'some of ' if inc == 'dec' else ''}the semantic
/// requirements of `${protocol}`, using `equalityOracle` to
/// generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition: ${'''`endIndex` is reachable from all
/// elements of `instances`.''' if inc == 'inc' else '''all
/// elements of `instances` are reachable from `startIndex`.'''}
public func check${inc.capitalize()}rementable<
Instances: Collection
where Instances.Iterator.Element : ${protocol}
>(
_ instances: Instances,
equalityOracle: (Instances.Index, Instances.Index) -> Bool,
${end}Index: Instances.Iterator.Element, ${TRACE}
) {
checkEquatable(instances, oracle: equalityOracle, ${trace})
for i in instances {
if i != ${end}Index {
let next = i.${successor}()
// ${successor} gets us a new index value
expectNotEqual(i, next, ${trace})
// Which is the same as if we apply _${successor}InPlace
var j = i
j._${successor}InPlace()
expectEqual(j, next, ${trace})
}
}
}
%end
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 where Instances.Iterator.Element : Comparable
>(
_ instances: Instances,
oracle: (Instances.Index, Instances.Index) -> ExpectedComparisonResult,
${TRACE}
) {
// Also checks that equality is consistent with comparison and that
// the oracle obeys the equality laws
checkEquatable(instances, oracle: { oracle($0, $1).isEQ() }, ${trace})
for i in instances.indices {
let x = instances[i]
expectFalse(x < x, ${trace})
expectFalse(x > x, ${trace})
expectTrue(x <= x, ${trace})
expectTrue(x >= x, ${trace})
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})
expectEqual(expected.isLT(), x < y, ${trace})
expectEqual(expected.isLE(), x <= y, ${trace})
expectEqual(expected.isGE(), x >= y, ${trace})
expectEqual(expected.isGT(), x > y, ${trace})
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})
}
}
}
}
}
public func checkComparable<T : Comparable>(
_ expected: ExpectedComparisonResult, _ lhs: T, _ rhs: T, ${TRACE}
) {
checkComparable(
[lhs, rhs],
oracle: { [[ .eq, expected], [ expected.flip(), .eq]][$0][$1] },
${trace})
}
/// 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
where
Instances.Iterator.Element : Strideable,
Strides.Iterator.Element == Instances.Iterator.Element.Stride
>(
_ instances: Instances, strides: Strides,
distanceOracle:
(Instances.Index, Instances.Index) -> Strides.Iterator.Element,
advanceOracle:
(Instances.Index, Strides.Index) -> Instances.Iterator.Element,
${TRACE}
) {
checkComparable(
instances,
oracle: {
let d = distanceOracle($1, $0);
return d < 0 ? .lt : d == 0 ? .eq : .gt
},
${trace})
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 struct CollectionMisuseResiliencyChecks {
public enum FailureKind {
case none
case trap
case expectationFailure
}
public var callNextOnExhaustedGenerator: Bool = true
public var creatingOutOfBoundsIndicesBehavior: FailureKind = .trap
public var subscriptOnOutOfBoundsIndicesBehavior: FailureKind = .trap
public var subscriptRangeOnOutOfBoundsRangesBehavior: FailureKind = .trap
public static var all: CollectionMisuseResiliencyChecks {
return CollectionMisuseResiliencyChecks()
}
public static var none: CollectionMisuseResiliencyChecks {
return CollectionMisuseResiliencyChecks(
callNextOnExhaustedGenerator: false,
creatingOutOfBoundsIndicesBehavior: .none,
subscriptOnOutOfBoundsIndicesBehavior: .none,
subscriptRangeOnOutOfBoundsRangesBehavior: .none)
}
}
internal func _checkIncrementalAdvance<
Instances : Collection
where
Instances.Iterator.Element : ForwardIndex
>(
_ instances: Instances,
equalityOracle: (Instances.Index, Instances.Index) -> Bool,
limit: Instances.Iterator.Element,
sign: Instances.Iterator.Element.Distance, // 1 or -1
next: (Instances.Iterator.Element) -> Instances.Iterator.Element,
${TRACE}
) {
for i in instances {
let d = sign > 0 ? i.distance(to: limit) : -limit.distance(to: i)
var offset: Instances.Iterator.Element.Distance = 0
for _ in 0...(d * sign).toIntMax() {
let j = i.advanced(by: offset)
let k = i.advanced(by: offset + sign, limit: limit)
let jAtLimit = offset == d
if jAtLimit {
expectEqual(limit, j, ${trace})
}
expectEqual(jAtLimit ? j : next(j), k, ${trace})
offset += sign
}
}
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `ForwardIndex`, using `equalityOracle` to
/// generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition: `endIndex` is reachable from all elements of
/// `instances`
public func checkForwardIndex<
Instances : Collection
where
Instances.Iterator.Element : ForwardIndex
>(
_ instances: Instances,
equalityOracle: (Instances.Index, Instances.Index) -> Bool,
endIndex: Instances.Iterator.Element, ${TRACE}
) {
typealias Index = Instances.Iterator.Element
checkIncrementable(
instances, equalityOracle: equalityOracle, endIndex: endIndex, ${trace})
_checkIncrementalAdvance(
instances, equalityOracle: equalityOracle, limit: endIndex,
sign: 1, next: { $0.successor() }, ${trace})
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `BidirectionalIndex`, using `equalityOracle`
/// to generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition:
/// - all elements of `instances` are reachable from `startIndex`.
/// - `endIndex` is reachable from all elements of `instances`.
public func checkBidirectionalIndex<
Instances: Collection
where
Instances.Iterator.Element : BidirectionalIndex
>(
_ instances: Instances,
equalityOracle: (Instances.Index, Instances.Index) -> Bool,
startIndex: Instances.Iterator.Element,
endIndex: Instances.Iterator.Element,
${TRACE}
) {
typealias Index = Instances.Iterator.Element
checkForwardIndex(
instances, equalityOracle: equalityOracle, endIndex: endIndex)
checkDecrementable(
instances, equalityOracle: equalityOracle, startIndex: startIndex, ${trace})
_checkIncrementalAdvance(
instances, equalityOracle: equalityOracle, limit: startIndex,
sign: -1, next: { $0.predecessor() }, ${trace})
}
/// Test that the elements of `instances` satisfy the semantic
/// requirements of `RandomAccessIndex`, using
/// `advanceOracle` and 'distanceOracle' to generate expectations
/// about the results of `advanced(by:)` and `distance(to:)` from pairs of
/// positions in `instances` and `distances`.
///
/// - Precondition:
/// - all elements of `instances` are reachable from `startIndex`.
/// - `endIndex` is reachable from all elements of `instances`.
public func checkRandomAccessIndex<
Instances : Collection, Distances : Collection
where
Instances.Iterator.Element : RandomAccessIndex,
Distances.Iterator.Element == Instances.Iterator.Element.Distance,
Instances.Iterator.Element.Distance == Instances.Iterator.Element.Stride
>(
_ instances: Instances, distances: Distances,
distanceOracle:
(Instances.Index, Instances.Index) -> Distances.Iterator.Element,
advanceOracle:
(Instances.Index, Distances.Index) -> Instances.Iterator.Element,
startIndex: Instances.Iterator.Element,
endIndex: Instances.Iterator.Element,
${TRACE}
) {
checkBidirectionalIndex(
instances, equalityOracle: { distanceOracle($0, $1) == 0 },
startIndex: startIndex, endIndex: endIndex, ${trace})
checkStrideable(
instances, strides: distances,
distanceOracle: distanceOracle,
advanceOracle: advanceOracle, ${trace})
}
// Generate two overloads: one for Array (which will get
// picked up when the caller passes a literal), and another that
// accepts any appropriate Collection type.
% for genericParam, Element, Expected in zip(
% ('Expected: Collection', 'Element'),
% ('Expected.Iterator.Element', 'Element'),
% ('Expected', 'Array<Element>')):
public func checkIterator<
${genericParam}, I : IteratorProtocol
where I.Element == ${Element}
>(
_ expected: ${Expected},
_ iterator: I,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
sameValue: (${Element}, ${Element}) -> Bool
) {
// Copying a `IteratorProtocol` is allowed.
var mutableGen = iterator
var actual: [${Element}] = []
while let e = mutableGen.next() {
actual.append(e)
}
expectEqualSequence(
expected, actual, ${trace}, sameValue: sameValue)
if resiliencyChecks.callNextOnExhaustedGenerator {
// Having returned `.None` once, a `IteratorProtocol` should not generate more
// elements.
for _ in 0..<10 {
expectEmpty(mutableGen.next(), ${trace})
}
}
}
public func checkIterator<
${genericParam}, I : IteratorProtocol
where I.Element == ${Element}, ${Element} : Equatable
>(
_ expected: ${Expected},
_ iterator: I,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
checkIterator(
expected, iterator, ${trace},
resiliencyChecks: resiliencyChecks, showFrame: false
) { $0 == $1 }
}
public func checkSequence<
${genericParam}, S : Sequence
where
S.Iterator.Element == ${Element}
>(
_ expected: ${Expected},
_ sequence: S,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
sameValue: (${Element}, ${Element}) -> Bool
) {
let expectedCount: Int = numericCast(expected.count)
checkIterator(
expected, sequence.makeIterator(), ${trace},
resiliencyChecks: resiliencyChecks,
sameValue: sameValue)
expectGE(
expectedCount, sequence.underestimatedCount, ${trace})
// Check that _copyContents does the right thing if we can do so
// without destroying the sequence.
sequence._preprocessingPass { () -> Void in
var count = 0
for _ in sequence { count += 1 }
let buf = UnsafeMutablePointer<S.Iterator.Element>(allocatingCapacity: count)
let end = sequence._copyContents(initializing: buf)
expectTrue(end == buf + count, "_copyContents returned the wrong value")
var j = expected.startIndex
for i in 0..<(end - buf) {
expectTrue(sameValue(expected[j], buf[i]))
j = j.successor()
}
buf.deinitialize(count: end - buf)
buf.deallocateCapacity(count)
}
}
public func checkSequence<
${genericParam}, S : Sequence
where
S.Iterator.Element == ${Element},
S.Iterator.Element : Equatable
>(
_ expected: ${Expected},
_ sequence: S,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
checkSequence(
expected, sequence, ${trace},
resiliencyChecks: resiliencyChecks, showFrame: false
) { $0 == $1 }
}
%for traversal in ['Forward', 'Bidirectional', 'RandomAccess']:
public func check${traversal}Collection<
${genericParam}, C : Collection
where
C.Iterator.Element == ${Element},
C.Index : ${traversal}Index
% if traversal == 'RandomAccess':
, C.Index.Stride == C.Index.Distance
% end
>(
_ expected: ${Expected}, _ collection: C,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
sameValue: (${Element}, ${Element}) -> Bool
) {
// A `Collection` is a multi-pass `Sequence`.
for _ in 0..<3 {
checkSequence(
expected, collection, ${trace},
resiliencyChecks: resiliencyChecks, sameValue: sameValue)
}
// Advances up to 1 positions without passing endIndex. Don't use
// advanced(by: n) to do this because it's under test here.
let next = { $0 == collection.endIndex ? $0 : $0.successor() }
// advances up to 5 positions without passing endIndex. Picking a
// small constant to avoid complexity explosion on large input
// collections.
let next5 = { next(next(next(next(next($0))))) }
let partWay0 = next5(collection.startIndex)
let partWay1 = next5(partWay0)
% if traversal == 'Forward':
checkForwardIndex(
collection.startIndex..<partWay0, equalityOracle: { $0 == $1 },
endIndex: partWay1, ${trace})
% elif traversal == 'Bidirectional':
checkBidirectionalIndex(
partWay0..<partWay1, equalityOracle: { $0 == $1 },
startIndex: collection.startIndex,
endIndex: next5(partWay1), ${trace})
% else:
% assert(traversal == 'RandomAccess')
typealias Distance = C.Index.Distance
let count: Distance = collection.count
let offset0 = min(5, count)
let offset1 = min(10, count)
let offset2 = min(15, count)
let distanceCandidates: [Distance] = [
-11, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 11]
let distances = distanceCandidates.filter { (x: Distance) -> Bool in
x + offset0 >= 0 && x + offset1 <= count
}
func nextN(_ n: C.Index.Distance, _ i: C.Index) -> C.Index {
var i = i
if n < 0 {
for _ in 0 ..< -(n.toIntMax()) {
i -= 1
}
}
else {
for _ in 0..<n.toIntMax() {
i += 1
}
}
return i
}
let instances = Array(partWay0..<partWay1)
typealias Distances = [Distance]
checkRandomAccessIndex(
instances,
distances: distances,
distanceOracle: { (x:Int,y:Int) in Distance(IntMax(y - x)) },
advanceOracle: { x,y in nextN(distances[y], instances[x]) },
startIndex: collection.startIndex,
endIndex: next5(partWay1), ${trace})
% end
let expectedArray = Array(expected)
expectEqual(
expectedArray.count.toIntMax(), collection.count.toIntMax(), ${trace})
for _ in 0..<3 {
if true {
let startIndex = collection.startIndex
let endIndex = collection.endIndex
for _ in collection.indices {
expectEqual(
startIndex, collection.startIndex,
"Iteration should not change startIndex",
stackTrace: ${stackTrace})
expectEqual(
endIndex, collection.endIndex,
"Iteration should not change endIndex",
stackTrace: ${stackTrace})
}
}
var allIndices = Array(collection.indices)
if expectedArray.count >= 2 {
for i in 0..<allIndices.count-1 {
let successor1 = allIndices[i].successor()
var successor2 = allIndices[i]
successor2 = successor2.successor()
var successor3 = allIndices[i]
successor3 = successor3.successor()
for s in [ successor1, successor2, successor3 ] {
expectEqual(allIndices[i + 1], s, ${trace})
expectEqual(
expectedArray[i + 1], collection[s], ${trace}, sameValue: sameValue)
}
}
% if traversal == "Bidirectional":
for i in 1..<allIndices.count {
let predecessor1 = allIndices[i].predecessor()
var predecessor2 = allIndices[i]
predecessor2 = predecessor2.predecessor()
var predecessor3 = allIndices[i]
predecessor3 = predecessor3.predecessor()
for p in [ predecessor1, predecessor2, predecessor3 ] {
expectEqual(allIndices[i - 1], p, ${trace})
expectEqual(
expectedArray[i - 1], collection[p], ${trace}, sameValue: sameValue)
}
}
for i in 1..<allIndices.count {
var index = allIndices[i]
index = index.predecessor()
index = index.successor()
expectEqual(allIndices[i], index, ${trace})
expectEqual(
expectedArray[i], collection[index], ${trace}, sameValue: sameValue)
}
% end
}
if true {
var allIndices2: [C.Index] = []
for i in collection.indices {
allIndices2.append(i)
}
expectEqualSequence(
allIndices, allIndices2, "iteration should not invalidate indices",
stackTrace: ${stackTrace})
expectEqualSequence(
expectedArray, allIndices.map { collection[$0] },
stackTrace: ${stackTrace}, sameValue: sameValue)
expectEqualSequence(
expectedArray, allIndices2.map { collection[$0] },
stackTrace: ${stackTrace}, sameValue: sameValue)
}
}
// FIXME: more checks for bidirectional and random access collections.
}
public func check${traversal}Collection<
${genericParam}, C : Collection
where
C.Iterator.Element == ${Element},
C.Index : ${traversal}Index,
${Element} : Equatable
% if traversal == 'RandomAccess':
, C.Index.Stride == C.Index.Distance
% end
>(
_ expected: ${Expected}, _ collection: C,
${TRACE},
resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
check${traversal}Collection(
expected, collection, ${trace},
resiliencyChecks: resiliencyChecks) { $0 == $1 }
}
% end
// FIXME: merge into checkCollection()
public func checkSliceableWithBidirectionalIndex<
${genericParam}, S : Collection
where
S.Iterator.Element == ${Element},
S.SubSequence.Iterator.Element == ${Element},
S.Index : BidirectionalIndex,
S.SubSequence : Collection,
S.SubSequence.Index : BidirectionalIndex,
${Element} : Equatable
>(
_ expected: ${Expected}, _ sliceable: S, ${TRACE}
) {
// A `Sliceable` is a `Collection`.
checkBidirectionalCollection(expected, sliceable, ${trace})
let expectedArray = Array(expected)
var start = sliceable.startIndex
for startNumericIndex in 0...expectedArray.count {
if start != sliceable.endIndex {
start = start.successor()
start = start.predecessor()
start = start.successor()
start = start.predecessor()
}
var end = start
for endNumericIndex in startNumericIndex...expectedArray.count {
if end != sliceable.endIndex {
end = end.successor()
end = end.predecessor()
end = end.successor()
end = end.predecessor()
}
let expectedSlice = expectedArray[startNumericIndex..<endNumericIndex]
let slice = sliceable[start..<end]
checkBidirectionalCollection(expectedSlice, slice, ${trace})
if end != sliceable.endIndex {
end = end.successor()
}
}
if start != sliceable.endIndex {
start = start.successor()
}
}
}
% end
public func nthIndex<C: Collection>(_ x: C, _ n: Int) -> C.Index {
return x.startIndex.advanced(by: numericCast(n))
}
public func nth<C: Collection>(_ x: C, _ n: Int) -> C.Iterator.Element {
return x[nthIndex(x, n)]
}
public func checkRangeReplaceable<
C: RangeReplaceableCollection,
N: Collection
where
C.Iterator.Element : Equatable,
C.Iterator.Element == N.Iterator.Element
>(
_ makeCollection: () -> C,
_ makeNewValues: (Int) -> N
) {
typealias A = C
// First make an independent copy of the array that we can use for
// comparison later.
let source = Array<A.Iterator.Element>(makeCollection())
for (ix, i) in source.indices.enumerated() {
for (jx_, j) in (i..<source.endIndex).enumerated() {
let jx = jx_ + ix
let oldCount = jx - ix
for newCount in 0..<(2 * oldCount) {
let newValues = makeNewValues(newCount)
func reportFailure(_ a: inout A, _ message: String) {
print("\(message) when replacing indices \(ix)...\(jx)")
print(" in \(Array(source)) with \(Array(newValues))")
print(" yielding \(Array(a))")
print("====================================")
expectTrue(false)
}
var a = makeCollection()
a.replaceSubrange(nthIndex(a, ix)..<nthIndex(a, jx), with: newValues)
let growth = newCount - oldCount
let expectedCount = source.count + growth
let actualCount = numericCast(a.count) as Int
if actualCount != expectedCount {
reportFailure(
&a, "\(actualCount) != expected count \(expectedCount)")
}
for (kx, k) in a.indices.enumerated() {
let expectedValue = kx < ix ? nth(source, kx)
: kx < jx + growth ? nth(newValues, kx - ix)
: nth(source, kx - growth)
if a[k] != expectedValue {
reportFailure(
&a,
// FIXME: why do we need to break this string into two parts?
"a[\(kx)] = "
+ "\(a[k]) != expected value \(expectedValue)")
}
}
}
}
}
}
public func expectEqualSequence<
Expected: Sequence,
Actual: Sequence
where
Expected.Iterator.Element == Actual.Iterator.Element,
Expected.Iterator.Element : Equatable
>(_ expected: Expected, _ actual: Actual, ${TRACE}) {
expectEqualSequence(expected, actual, ${trace}) { $0 == $1 }
}
public func expectEqualSequence<
Expected : Sequence,
Actual : Sequence,
T : Equatable,
U : Equatable
where
Expected.Iterator.Element == Actual.Iterator.Element,
Expected.Iterator.Element == (T, U)
>(_ expected: Expected, _ actual: Actual, ${TRACE}) {
expectEqualSequence(
expected, actual, ${trace}) {
(lhs: (T, U), rhs: (T, U)) -> Bool in
lhs.0 == rhs.0 && lhs.1 == rhs.1
}
}
public func expectEqualSequence<
Expected: Sequence,
Actual: Sequence
where
Expected.Iterator.Element == Actual.Iterator.Element
>(_ expected: Expected, _ actual: Actual, ${TRACE},
sameValue: (Expected.Iterator.Element, Expected.Iterator.Element) -> Bool) {
if !expected.elementsEqual(actual, isEquivalent: sameValue) {
expectationFailure("expected elements: \"\(expected)\"\n"
+ "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
trace: ${trace})
}
}
public func expectEqualsUnordered<
Expected : Sequence,
Actual : Sequence
where
Expected.Iterator.Element == Actual.Iterator.Element
>(
_ expected: Expected, _ actual: Actual, ${TRACE},
compare: (Expected.Iterator.Element, Expected.Iterator.Element)
-> ExpectedComparisonResult
) {
let x: [Expected.Iterator.Element] =
expected.sorted(isOrderedBefore: compose(compare, { $0.isLT() }))
let y: [Actual.Iterator.Element] =
actual.sorted(isOrderedBefore: compose(compare, { $0.isLT() }))
expectEqualSequence(
x, y, ${trace}, sameValue: compose(compare, { $0.isEQ() }))
}
public func expectEqualsUnordered<
Expected : Sequence,
Actual : Sequence
where
Expected.Iterator.Element == Actual.Iterator.Element,
Expected.Iterator.Element : Comparable
>(
_ expected: Expected, _ actual: Actual, ${TRACE}
) {
expectEqualsUnordered(expected, actual, ${trace}) {
$0 < $1 ? .lt : $0 == $1 ? .eq : .gt
}
}
public func expectEqualsUnordered<T : Comparable>(
_ expected: [T], _ actual: [T], ${TRACE}
) {
let x = expected.sorted()
let y = actual.sorted()
expectEqualSequence(x, y, ${trace})
}
/// 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
}
func == <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return lhs.first == rhs.first && lhs.second == rhs.second
}
func < <T>(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
where
Actual.Iterator.Element == (key: T, value: T),
Expected.Iterator.Element == (T, T)
>(
_ expected: Expected, _ actual: Actual, ${TRACE}
) {
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(isOrderedBefore: comparePairLess)
let y: [(T, T)] =
actual.map { ($0.0, $0.1) }
.sorted(isOrderedBefore: comparePairLess)
func comparePairEquals(_ lhs: (T, T), rhs: (key: T, value: T)) -> Bool {
return lhs.0 == rhs.0 && lhs.1 == rhs.1
}
expectEqualSequence(x, y, ${trace}, 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(
_ expected: [UInt32], _ actual: String, ${TRACE}) {
let actualUnicodeScalars = Array(
actual.unicodeScalars.lazy.map { $0.value })
if !expected.elementsEqual(actualUnicodeScalars) {
expectationFailure(
"expected elements: \"\(asHex(expected))\"\n"
+ "actual: \"\(asHex(actualUnicodeScalars))\"",
trace: ${trace})
}
}
public func expectPrinted<T>(
expectedOneOf patterns: [String], _ object: T, ${TRACE}
) {
let actual = String(object)
if !patterns.contains(actual) {
expectationFailure(
"expected: any of \(String(reflecting: patterns))\n"
+ "actual: \(String(reflecting: actual))",
trace: ${trace})
}
}
public func expectPrinted<T>(
_ expected: String, _ object: T, ${TRACE}
) {
expectPrinted(expectedOneOf: [expected], object, ${trace})
}
public func expectDebugPrinted<T>(
expectedOneOf patterns: [String], _ object: T, ${TRACE}
) {
expectPrinted(expectedOneOf: patterns, String(reflecting: object), ${trace})
}
public func expectDebugPrinted<T>(
_ expected: String, _ object: T, ${TRACE}
) {
expectDebugPrinted(expectedOneOf: [expected], object, ${trace})
}
func compose<A, B, C>(_ f: A -> B, _ g: B -> C) -> A -> C {
return { a in
return g(f(a))
}
}
/// A type that does not conform to any protocols.
///
/// This type can be used to check that generic functions don't rely on any
/// conformances.
public struct OpaqueValue<Underlying> {
public var value: Underlying
public var identity: Int
public init(_ value: Underlying) {
self.value = value
self.identity = 0
}
public init(_ value: Underlying, identity: Int) {
self.value = value
self.identity = identity
}
}
/// A type that conforms only to `Equatable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalEquatableValue : Equatable {
public static var timesEqualEqualWasCalled: Int = 0
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
}
public func == (
lhs: MinimalEquatableValue,
rhs: MinimalEquatableValue
) -> Bool {
MinimalEquatableValue.timesEqualEqualWasCalled += 1
return lhs.value == rhs.value
}
/// A type that conforms only to `Equatable` and `Comparable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalComparableValue : Equatable, Comparable {
public static var timesEqualEqualWasCalled = ResettableValue(0)
public static var timesLessWasCalled = ResettableValue(0)
public static var equalImpl =
ResettableValue<(Int, Int) -> Bool>({ $0 == $1 })
public static var lessImpl =
ResettableValue<(Int, Int) -> Bool>({ $0 < $1 })
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
}
public func == (
lhs: MinimalComparableValue,
rhs: MinimalComparableValue
) -> Bool {
MinimalComparableValue.timesEqualEqualWasCalled.value += 1
return MinimalComparableValue.equalImpl.value(lhs.value, rhs.value)
}
public func < (
lhs: MinimalComparableValue,
rhs: MinimalComparableValue
) -> Bool {
MinimalComparableValue.timesLessWasCalled.value += 1
return MinimalComparableValue.lessImpl.value(lhs.value, rhs.value)
}
/// A type that conforms only to `Comparable` and `ForwardIndexType`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalComparableIndexValue : Comparable, ForwardIndex {
public static var timesEqualEqualWasCalled = ResettableValue(0)
public static var timesLessWasCalled = ResettableValue(0)
public func successor() -> MinimalComparableIndexValue {
return MinimalComparableIndexValue(value.successor())
}
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
}
public func == (
lhs: MinimalComparableIndexValue,
rhs: MinimalComparableIndexValue
) -> Bool {
MinimalComparableIndexValue.timesEqualEqualWasCalled.value += 1
return lhs.value == rhs.value
}
public func < (
lhs: MinimalComparableIndexValue,
rhs: MinimalComparableIndexValue
) -> Bool {
MinimalComparableIndexValue.timesLessWasCalled.value += 1
return lhs.value < rhs.value
}
% for kind in ['Value', 'Class']:
% Self = 'MinimalHashable%s' % kind
/// A type that conforms only to `Equatable` and `Hashable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct ${Self} : Equatable, Hashable {
public static var timesEqualEqualWasCalled: Int = 0
public static var timesHashValueWasCalled: Int = 0
public var value: Int
public var identity: Int
public init(_ value: Int) {
self.value = value
self.identity = 0
}
public init(_ value: Int, identity: Int) {
self.value = value
self.identity = identity
}
public var hashValue: Int {
${Self}.timesHashValueWasCalled += 1
return value.hashValue
}
}
public func == (
lhs: ${Self},
rhs: ${Self}
) -> Bool {
${Self}.timesEqualEqualWasCalled += 1
return lhs.value == rhs.value
}
% end
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End: