//===--- 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''' # When the parameter list would start with a ${TRACE}, we use # ${TRACE1} instead, to avoid the warning about an extraneous # '_' on the first parameter. TRACE1 = TRACE.replace(' _ ', ' ', 1) 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(${TRACE1}, 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) -> OpaqueValue { return element } public func identityEq(element: MinimalEquatableValue) -> MinimalEquatableValue { return element } public func identityComp(element: MinimalComparableValue) -> MinimalComparableValue { return element } public func expectEqual(expected: T, _ actual: T, ${TRACE}) { expectEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1} } public func expectEqual( 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( 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(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: // Array->NSArray implicit conversion insanity public func expectOptionalEqual( expected: T, _ actual: T?, ${TRACE} ) { expectOptionalEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1} } public func expectOptionalEqual( 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(expected: T?, _ actual: T?, ${TRACE}) { if (actual == nil) != (expected == nil) || actual != nil && expected! != actual! { expectationFailure( "expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n" + "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))", trace: ${trace}) } } // Array is not Equatable if T is. Provide additional overloads. // Same for Dictionary. %for (Generic, EquatableType) in [ % ('', 'ContiguousArray'), % ('', 'ArraySlice'), % ('', 'Array'), % ('', 'Dictionary')]: 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.Type, _ x: inout T) {} public func expectEqualType(_: 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: 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 collectionType: X.Type, iteratorType: Iterator.Type, subSequenceType: SubSequence.Type, indexType: Index.Type ) {} public func expectForwardIndexType(x: X) -> X { return x } public func expectIsBooleanType(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(${TRACE1}) { 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(value: T?, ${TRACE}) { if value != nil { expectationFailure( "expected optional to be empty\nactual: \"\(value)\"", trace: ${trace}) } } public func expectNotEmpty(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 } } } 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:") print("$ \(Process.arguments[0]) " + "--stdlib-unittest-in-process --stdlib-unittest-filter \"\(fullTestName)\"") } var _allTestSuites: [TestSuite] = [] var _testSuiteNameToIndex: [String : Int] = [:] let _stdlibUnittestStreamPrefix = "__STDLIB_UNITTEST__" @_silgen_name("swift_stdlib_installTrapInterceptor") func _stdlib_installTrapInterceptor() func _childProcess() { _stdlib_installTrapInterceptor() while let line = _stdlib_getline() { let parts = line._split(separator: ";") let testSuiteName = parts[0] let testName = parts[1] let testSuite = _allTestSuites[_testSuiteNameToIndex[testSuiteName]!] _anyExpectFailed = false testSuite._runTest(testName) 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. mutating func _runTestInChild(testSuite: TestSuite, _ testName: String) -> (anyExpectFailed: Bool, seenExpectCrash: Bool, status: ProcessTerminationStatus?, crashStdout: [String], crashStderr: [String]) { if _pid <= 0 { _spawnChild() } print("\(testSuite.name);\(testName)", 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)") } 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)") } 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) } 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 { let fullTestName = "\(testSuite.name).\(t.name)" if let filter = _filter where findSubstring(fullTestName, filter) == nil { continue } let activeSkips = t.getActiveSkipPredicates() if !activeSkips.isEmpty { skippedTests += [ t.name ] print("[ SKIP ] \(fullTestName) (skip: \(activeSkips))") continue } 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(t.name) } } else { (_anyExpectFailed, expectCrash, childTerminationStatus, crashStdout, crashStderr) = _runTestInChild(testSuite, t.name) } // 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 expectedCrashOutput in t.crashOutputMatches { var found = false for s in crashOutput { if findSubstring(s, expectedCrashOutput) != nil { found = true break } } if !found { print("did not find expected string after crash: \(expectedCrashOutput.debugDescription)") testPassed = false } } } // Apply XFAILs. switch (testPassed, expectXFail) { case (true, false): print("[ OK ] \(fullTestName)") case (true, true): uxpassedTests += [ t.name ] print("[ UXPASS ] \(fullTestName)") case (false, false): failedTests += [ t.name ] print("[ FAIL ] \(fullTestName)") case (false, true): 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 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(testName: String) { PersistentState.ranSomething = true for r in _allResettables { r.reset() } LifetimeTracked.instances = 0 if let f = _testSetUpCode { f() } let test = _testByName(testName) test.code() 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]!] } 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: () -> Void /// 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() } } } public struct _TestBuilder { let _testSuite: TestSuite var _name: String var _data: _Data = _Data() 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 } public func code(testFunction: () -> Void) { _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: testFunction)) _testSuite._testNameToIndex[_name] = _testSuite._tests.count - 1 } } 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) -> UnsafePointer func _stdlib_getSystemVersionPlistProperty(propertyName: String) -> String? { let cs = _stdlib_getSystemVersionPlistPropertyImpl(propertyName) return (cs != nil) ? String(cString: cs) : nil } #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, reason: String) case osxBugFix(Int, Int, Int, reason: String) case osxBugFixRange(Int, Int, Range, reason: String) case iOSAny(/*reason:*/ String) case iOSMajor(Int, reason: String) case iOSMinor(Int, Int, reason: String) case iOSMinorRange(Int, Range, reason: String) case iOSBugFix(Int, Int, Int, reason: String) case iOSBugFixRange(Int, Int, Range, 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, reason: String) case tvOSBugFix(Int, Int, Int, reason: String) case tvOSBugFixRange(Int, Int, Range, 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, reason: String) case watchOSBugFix(Int, Int, Int, reason: String) case watchOSBugFixRange(Int, Int, Range, 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( 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( 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( 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')): 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(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.. 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..= 2 { for i in 0..( 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..(x: C, _ n: Int) -> C.Index { return x.startIndex.advanced(by: numericCast(n)) } public func nth(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(makeCollection()) for (ix, i) in source.indices.enumerated() { for (jx_, j) in (i..(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( 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 : Comparable { init(_ first: T, _ second: T) { self.first = first self.second = second } var first: T var second: T } func == (lhs: Pair, rhs: Pair) -> Bool { return lhs.first == rhs.first && lhs.second == rhs.second } func < (lhs: Pair, rhs: Pair) -> 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( 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( 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( expected: String, _ object: T, ${TRACE} ) { expectPrinted(expectedOneOf: [expected], object, ${trace}) } public func expectDebugPrinted( expectedOneOf patterns: [String], _ object: T, ${TRACE} ) { expectPrinted(expectedOneOf: patterns, String(reflecting: object), ${trace}) } public func expectDebugPrinted( expected: String, _ object: T, ${TRACE} ) { expectDebugPrinted(expectedOneOf: [expected], object, ${trace}) } func compose(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 { 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: