//===--- StdlibUnittest.swift.gyb -----------------------------*- swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 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 SwiftPrivateDarwinExtras #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin #elseif os(Linux) import Glibc #endif #if _runtime(_ObjC) import ObjectiveC #endif public struct SourceLoc { public let file: String public let line: UWord public let comment: String? public init(_ file: String, _ line: UWord, comment: String? = nil) { self.file = file self.line = line self.comment = comment } public func withCurrentLoc( file: String = __FILE__, line: UWord = __LINE__ ) -> SourceLocStack { return SourceLocStack(self).with(SourceLoc(file, line)) } } public struct SourceLocStack { let locs: _UnitTestArray public init() { locs = [] } public init(_ loc: SourceLoc) { locs = [ loc ] } init(_locs: _UnitTestArray) { 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 withCurrentLoc( file: String = __FILE__, line: UWord = __LINE__ ) -> SourceLocStack { return with(SourceLoc(file, line)) } } func _printStackTrace(stackTrace: SourceLocStack?) { guard let s = stackTrace else { return } println("stacktrace:") for i in 0..( expected: T, _ actual: T, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { expectEqual(expected, actual, {$0 == $1}, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqual( expected: (T, U), _ actual: (T, U), stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { expectEqual(expected.0, actual.0, {$0 == $1}, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) expectEqual(expected.1, actual.1, {$0 == $1}, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqual( expected: T, _ actual: T, _ equal: (T,T)->Bool, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if !equal(expected, actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: \"\(expected)\" (of type \(_stdlib_getDemangledTypeName(expected)))") println("actual: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(expected)))") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectNotEqual( expected: T, _ actual: T, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if expected == actual { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("unexpected value: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } // Can not write a sane set of overloads using generics because of: // Array->NSArray implicit conversion insanity public func expectOptionalEqual( expected: T, _ actual: T?, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { if (actual == nil) || expected != actual! { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: \"\(expected)\" (of type \(_stdlib_getDemangledTypeName(expected)))") println("actual: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") println() } } public func expectEqual( expected: T?, _ actual: T?, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { if (actual == nil) != (expected == nil) || actual != nil && expected! != actual! { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: \"\(expected)\" (of type \(_stdlib_getDemangledTypeName(expected)))") println("actual: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") println() } } // Array is not Equatable if T is. Provide additional overloads. // Same for Dictionary. %for (Generic, EquatableType) in [ % ('', 'ContiguousArray'), % ('', '_UnitTestArray'), % ('', 'ArraySlice'), % ('', 'Array'), % ('', 'Dictionary')]: public func expectEqual${Generic}( expected: ${EquatableType}, _ actual: ${EquatableType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { expectEqual( expected, actual, // FIXME: Simpler closures don't work here due to // and { (x: ${EquatableType}, y: ${EquatableType})->Bool in x == y }, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqualSequence${Generic}( expected: ${EquatableType}, _ actual: ${EquatableType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { expectEqual( expected, actual, // FIXME: Simpler closures don't work here due to // and { (x: ${EquatableType}, y: ${EquatableType})->Bool in x == y }, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } func _expectNotEqual${Generic}( expected: ${EquatableType}, actual: ${EquatableType}, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if expected == actual { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("unexpected value: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectOptionalEqual${Generic}( expected: ${EquatableType}, _ actual: ${EquatableType}?, file: String = __FILE__, line: UWord = __LINE__ ) { if (actual == nil) || expected != actual! { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected: \"\(expected)\" (of type \(_stdlib_getDemangledTypeName(expected)))") println("actual: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") println() } } %end %for ComparableType in ['Int']: public func expectLT( expected: ${ComparableType}, _ actual: ${ComparableType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if !(expected < actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: \"\(expected)\"") println("actual: \"\(actual)\"") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectLE( expected: ${ComparableType}, _ actual: ${ComparableType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if !(expected <= actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: \"\(expected)\"") println("actual: \"\(actual)\"") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectGE( expected: ${ComparableType}, _ actual: ${ComparableType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if !(expected >= actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: \"\(expected)\"") println("actual: \"\(actual)\"") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } %end public func expectType(_: T.Type, inout _ x: T) {} public func isSequenceType(x: X) -> X { return x } public func expectIsBooleanType(inout x: X) -> X { return x } public struct AssertionResult : CustomStringConvertible, BooleanType { 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( stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("this code should not be executed") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } public func expectUnreachableCatch( error: _ErrorType, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("error should not be thrown: \"\(error)\"") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } %for BoolType in ['Bool', 'AssertionResult']: public func expectTrue( actual: ${BoolType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if !actual { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: true") println("actual: \(actual)") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectFalse( actual: ${BoolType}, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if actual { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected: false") println("actual: \(actual)") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } %end public func expectEmpty( value: Optional, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if value != nil { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected optional to be empty") println("actual: \"\(value)\"") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectNotEmpty( value: Optional, file: String = __FILE__, line: UWord = __LINE__ ) -> T? { if value == nil { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected optional to be non-empty") println() } return value } public func expectCrashLater() { println("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed)") var stderr = _Stderr() println("\(_stdlibUnittestStreamPrefix);expectCrash", &stderr) _seenExpectCrash = true } func _defaultTestSuiteFailedCallback() { abort() } var _testSuiteFailedCallback: () -> () = _defaultTestSuiteFailedCallback public func _setTestSuiteFailedCallback(callback: () -> ()) { _testSuiteFailedCallback = callback } extension ProcessTerminationStatus { var isSwiftTrap: Bool { switch self { case .Exit(var status): return false case .Signal(var signal): return CInt(signal) == SIGILL || CInt(signal) == SIGTRAP } } } func _stdlib_getline() -> String? { var result = _UnitTestArray() 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) { println("To debug, run:") println("$ \(Process.arguments[0]) " + "--stdlib-unittest-in-process --stdlib-unittest-filter \"\(fullTestName)\"") } var _allTestSuites: _UnitTestArray = [] var _testSuiteNameToIndex: [String : Int] = [:] let _stdlibUnittestStreamPrefix = "__STDLIB_UNITTEST__" @asmname("swift_stdlib_installTrapInterceptor") func _stdlib_installTrapInterceptor() func _childProcess() { _stdlib_installTrapInterceptor() while let line = _stdlib_getline() { let parts = line._split(";") let testSuiteName = parts[0] let testName = parts[1] let testSuite = _allTestSuites[_testSuiteNameToIndex[testSuiteName]!] _anyExpectFailed = false testSuite._runTest(testName) println("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed)") var stderr = _Stderr() println("\(_stdlibUnittestStreamPrefix);end", &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? init(runTestsInProcess: Bool, filter: String?) { self._runTestsInProcess = runTestsInProcess self._filter = filter } mutating func _spawnChild() { let (pid, childStdinFD, childStdoutFD, childStderrFD) = spawnChild([ "--stdlib-unittest-run-child" ]) _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: _UnitTestArray, crashStderr: _UnitTestArray) { if _pid <= 0 { _spawnChild() } println("\(testSuite.name);\(testName)", &_childStdin) let currentTest = testSuite._testByName(testName) if let stdinText = currentTest.stdinText { print(stdinText, &_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 = _UnitTestArray() var capturedCrashStderr = _UnitTestArray() 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 { println("StdlibUnittest: using filter: \(filter)") } for testSuite in _allTestSuites { var uxpassedTests = _UnitTestArray() var failedTests = _UnitTestArray() var skippedTests = _UnitTestArray() 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 ] println("[ SKIP ] \(fullTestName) (skip: \(activeSkips))") continue } let activeXFails = t.getActiveXFailPredicates() let expectXFail = !activeXFails.isEmpty let activeXFailsText = expectXFail ? " (XFAIL: \(activeXFails))" : "" println("[ RUN ] \(fullTestName)\(activeXFailsText)") var expectCrash = false var childTerminationStatus: ProcessTerminationStatus? = nil var crashStdout = _UnitTestArray() var crashStderr = _UnitTestArray() if _runTestsInProcess { if t.stdinText != nil { println("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 var testFailureExplanation = "" switch (_anyExpectFailed, childTerminationStatus, expectCrash) { case (_, .None, false): testPassed = !_anyExpectFailed case (_, .None, true): testPassed = false testFailureExplanation = "expecting a crash, but the test did not crash" case (_, .Some(let status), false): testPassed = false testFailureExplanation = "the test crashed unexpectedly" case (_, .Some(let status), 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 { println("did not find expected string after crash: \(expectedCrashOutput.debugDescription)") testPassed = false } } } // Apply XFAILs. switch (testPassed, expectXFail) { case (true, false): println("[ OK ] \(fullTestName)") case (true, true): uxpassedTests += [ t.name ] println("[ UXPASS ] \(fullTestName)") case (false, false): failedTests += [ t.name ] println("[ FAIL ] \(fullTestName)") case (false, true): println("[ XFAIL ] \(fullTestName)") } } if !uxpassedTests.isEmpty || !failedTests.isEmpty { println("\(testSuite.name): Some tests failed, aborting") println("UXPASS: \(uxpassedTests)") println("FAIL: \(failedTests)") println("SKIP: \(skippedTests)") if !uxpassedTests.isEmpty { _printDebuggingAdvice(uxpassedTests[0]) } if !failedTests.isEmpty { _printDebuggingAdvice(failedTests[0]) } _testSuiteFailedCallback() } else { println("\(testSuite.name): All tests passed") } } } } public func runAllTests() { struct PersistentState { static var runAllTestsWasCalled: Bool = false } if PersistentState.runAllTestsWasCalled { println("runAllTests() called twice. It is not allowed, aborting.") _testSuiteFailedCallback() return } PersistentState.runAllTestsWasCalled = 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 for var i = 0; i < Process.arguments.count(); { let arg = Process.arguments[i] if arg == "--stdlib-unittest-in-process" { runTestsInProcess = true ++i continue } if arg == "--stdlib-unittest-filter" { filter = Process.arguments[i + 1] i += 2 continue } if arg == "--help" { println( "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.") return } // FIXME: skipping unrecognized parameters. ++i } var parent = _ParentProcess( runTestsInProcess: runTestsInProcess, 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 } public func test(name: String, _ testFunction: () -> ()) { _TestBuilder(testSuite: self, name: name).code(testFunction) } public func test(name: String) -> _TestBuilder { return _TestBuilder(testSuite: self, name: name) } public func setUp(code: () -> ()) { _precondition(_testSetUpCode == nil, "set-up code already set") _testSetUpCode = code } public func tearDown(code: () -> ()) { _precondition(_testTearDownCode == nil, "tear-down code already set") _testTearDownCode = code } func _runTest(testName: String) { if let f = _testSetUpCode { f() } _testByName(testName).code() if let f = _testTearDownCode { f() } } func _testByName(testName: String) -> _Test { return _tests[_testNameToIndex[testName]!] } struct _Test { let name: String let xfail: _UnitTestArray let skip: _UnitTestArray let stdinText: String? let stdinEndsWithEOF: Bool let crashOutputMatches: [String] let code: () -> () /// Whether the test harness should stop reusing the child process after /// running this test. var canReuseChildProcessAfterTest: Bool { return stdinText == nil } func getActiveXFailPredicates() -> _UnitTestArray { return xfail.filter { $0.evaluate() } } func getActiveSkipPredicates() -> _UnitTestArray { return skip.filter { $0.evaluate() } } } public struct _TestBuilder { let _testSuite: TestSuite var _name: String var _data: _Data = _Data() class _Data { var _xfail: _UnitTestArray = [] var _skip: _UnitTestArray = [] var _stdinText: String? = nil var _stdinEndsWithEOF: Bool = false var _crashOutputMatches: [String] = [] } init(testSuite: TestSuite, name: String) { _testSuite = testSuite _name = name } 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: () -> ()) { _testSuite._tests.append(_Test( name: _name, 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: _UnitTestArray<_Test> = [] /// Code that is run before every test. var _testSetUpCode: (() -> ())? /// Code that is run after every test. var _testTearDownCode: (() -> ())? /// Maps test name to index in `_tests`. var _testNameToIndex: [String : Int] = [:] } #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) @asmname("swift_stdlib_getSystemVersionPlistProperty") func _stdlib_getSystemVersionPlistPropertyImpl( propertyName: UnsafePointer) -> UnsafePointer func _stdlib_getSystemVersionPlistProperty(propertyName: String) -> String? { return String.fromCString( _stdlib_getSystemVersionPlistPropertyImpl(propertyName)) } #endif public enum OSVersion : CustomStringConvertible { case OSX(major: Int, minor: Int, bugFix: Int) case iOS(major: Int, minor: Int, bugFix: Int) case iOSSimulator case Linux public var description: String { switch self { case OSX(var major, var minor, var bugFix): return "OS X \(major).\(minor).\(bugFix)" case iOS(var major, var minor, var bugFix): return "iOS \(major).\(minor).\(bugFix)" case iOSSimulator: return "iOSSimulator" case Linux: return "Linux" } } } func _parseDottedVersion(s: String) -> _UnitTestArray { return _UnitTestArray(lazy(s._split(".")).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(Linux) return .Linux #else let productName = _stdlib_getSystemVersionPlistProperty("ProductName")! let productVersion = _stdlib_getSystemVersionPlistProperty("ProductVersion")! let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion) switch productName { case "Mac OS X": return .OSX(major: major, minor: minor, bugFix: bugFix) case "iPhone OS": return .iOS(major: major, minor: minor, bugFix: bugFix) default: fatalError("could not determine OS version") } #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 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 LinuxAny(reason: String) public var description: String { switch self { case Custom(_, let reason): return "Custom(reason: \(reason))" 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 LinuxAny(reason: let reason): return "LinuxAny(*, reason: \(reason))" } } public func evaluate() -> Bool { switch self { case Custom(let predicate, _): return predicate() 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 LinuxAny: switch _getRunningOSVersion() { case .Linux: return true default: return false } } } } // // Helpers that verify invariants of various stdlib types. // public func checkEquatable( expectedEqual: Bool, _ lhs: T, _ rhs: T, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { // Test operator '==' that is found through witness tables. expectEqual( expectedEqual, lhs == rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) expectEqual( !expectedEqual, lhs != rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) } public func checkEquatable( expectedEqual: Bool, _ lhs: T, _ rhs: T, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { checkEquatable( expectedEqual, lhs, rhs, SourceLocStack().with(SourceLoc(file, line))) } public func checkHashable( expectedEqual: Bool, _ lhs: T, _ rhs: T, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { // Test operator '==' that is found through witness tables. expectEqual( expectedEqual, lhs == rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) expectEqual( !expectedEqual, lhs != rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) // Test 'hashValue'. // // If objects are not equal, then the hash value can be different or it can // collide. if expectedEqual { expectEqual(lhs.hashValue, rhs.hashValue, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) } } public func checkHashable( expectedEqual: Bool, _ lhs: T, _ rhs: T, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { checkHashable( expectedEqual, lhs, rhs, SourceLocStack(SourceLoc(file, line)), collectMoreInfo: collectMoreInfo) } 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 ">" } } } public func checkComparable( expected: ExpectedComparisonResult, _ lhs: T, _ rhs: T, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { expectEqual(expected.isLT(), lhs < rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) expectEqual(expected.isLE(), lhs <= rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) expectEqual(expected.isGE(), lhs >= rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) expectEqual(expected.isGT(), lhs > rhs, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo) } public func checkComparable( expected: ExpectedComparisonResult, _ lhs: T, _ rhs: T, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { checkComparable(expected, lhs, rhs, SourceLocStack(SourceLoc(file, line)), collectMoreInfo: collectMoreInfo) } public struct CollectionMisuseResiliencyChecks { public var callNextOnExhaustedGenerator: Bool = true public static var all: CollectionMisuseResiliencyChecks { return CollectionMisuseResiliencyChecks() } public static var none: CollectionMisuseResiliencyChecks { return CollectionMisuseResiliencyChecks( callNextOnExhaustedGenerator: false) } } // Generate two overloads: one for _UnitTestArray (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: CollectionType', 'Element'), % ('Expected.Generator.Element', 'Element'), % ('Expected', '_UnitTestArray')): public func checkGenerator< G : GeneratorType, ${genericParam} where ${Element} == G.Element >( expected: ${Expected}, _ generator: G, _ sameValue: (${Element}, ${Element}) -> Bool, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { // Copying a `GeneratorType` is allowed. var mutableGen = generator var actual: _UnitTestArray<${Element}> = [] while let e = mutableGen.next() { actual.append(e) } expectEqualSequence( expected, actual, sameValue, stackTrace: stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) if resiliencyChecks.callNextOnExhaustedGenerator { // Having returned `.None` once, a `GeneratorType` should not generate more // elements. for i in 0..<10 { expectEmpty( mutableGen.next(), stackTrace: stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) } } } public func checkGenerator< G : GeneratorType, ${genericParam} where ${Element} == G.Element, ${Element} : Equatable >( expected: ${Expected}, _ generator: G, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { checkGenerator( expected, generator, { $0 == $1 }, resiliencyChecks: resiliencyChecks, stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) } public func checkSequence< ${genericParam}, S : SequenceType where S.Generator.Element == ${Element} >( expected: ${Expected}, _ sequence: S, _ sameValue: (${Element}, ${Element}) -> Bool, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { let expectedCount: Int = numericCast(expected.count()) checkGenerator( expected, sequence.generate(), sameValue, resiliencyChecks: resiliencyChecks, stackTrace.withCurrentLoc()) expectGE( expectedCount, sequence.underestimateCount(), stackTrace: stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) } public func checkSequence< ${genericParam}, S : SequenceType where S.Generator.Element == ${Element} >( expected: ${Expected}, _ sequence: S, _ sameValue: (${Element}, ${Element}) -> Bool, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { checkSequence( expected, sequence, sameValue, resiliencyChecks: resiliencyChecks, SourceLocStack().with(SourceLoc(file, line)), collectMoreInfo: collectMoreInfo) } public func checkSequence< ${genericParam}, S : SequenceType where S.Generator.Element == ${Element}, ${Element} : Equatable >( expected: ${Expected}, _ sequence: S, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { checkSequence( expected, sequence, { $0 == $1 }, resiliencyChecks: resiliencyChecks, stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) } public func checkSequence< ${genericParam}, S : SequenceType where S.Generator.Element == ${Element}, ${Element} : Equatable >( expected: ${Expected}, _ sequence: S, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { checkSequence( expected, sequence, { $0 == $1 }, resiliencyChecks: resiliencyChecks, SourceLocStack().with(SourceLoc(file, line)), collectMoreInfo: collectMoreInfo) } %for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: public func check${traversal}Collection< ${genericParam}, C : CollectionType where C.Generator.Element == ${Element}, C.Index : ${traversal}IndexType >( expected: ${Expected}, _ collection: C, _ sameValue: (${Element}, ${Element}) -> Bool, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { // A `CollectionType` is a multi-pass `SequenceType`. for i in 0..<3 { checkSequence( expected, collection, sameValue, resiliencyChecks: resiliencyChecks, stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) } let expectedArray = Array(expected) expectEqual( expectedArray.count().toIntMax(), collection.count().toIntMax(), stackTrace: stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) for i in 0..<3 { if true { let startIndex = collection.startIndex let endIndex = collection.endIndex for i in collection.indices { expectEqual(startIndex, collection.startIndex, stackTrace: stackTrace.withCurrentLoc()) { "Iteration should not change startIndex" } expectEqual(endIndex, collection.endIndex, stackTrace: stackTrace.withCurrentLoc()) { "Iteration should not change endIndex" } } } var allIndices: [C.Index] = [] for i in collection.indices { allIndices.append(i) } if expectedArray.count() >= 2 { for i in 0..( expected: ${Expected}, _ collection: C, _ sameValue: (${Element}, ${Element}) -> Bool, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { check${traversal}Collection( expected, collection, sameValue, resiliencyChecks: resiliencyChecks, SourceLocStack().with(SourceLoc(file, line)), collectMoreInfo: collectMoreInfo) } public func check${traversal}Collection< ${genericParam}, C : CollectionType where C.Generator.Element == ${Element}, C.Index : ${traversal}IndexType, ${Element} : Equatable >( expected: ${Expected}, _ collection: C, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, _ stackTrace: SourceLocStack, collectMoreInfo: (()->String)? = nil ) { check${traversal}Collection( expected, collection, { $0 == $1 }, resiliencyChecks: resiliencyChecks, stackTrace.withCurrentLoc(), collectMoreInfo: collectMoreInfo) } public func check${traversal}Collection< ${genericParam}, C : CollectionType where C.Generator.Element == ${Element}, C.Index : ${traversal}IndexType, ${Element} : Equatable >( expected: ${Expected}, _ collection: C, resiliencyChecks: CollectionMisuseResiliencyChecks = .all, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { check${traversal}Collection( expected, collection, { $0 == $1 }, resiliencyChecks: resiliencyChecks, SourceLocStack().with(SourceLoc(file, line)), collectMoreInfo: collectMoreInfo) } % end public func checkSliceableWithBidirectionalIndex< ${genericParam}, S : Sliceable where S.Generator.Element == ${Element}, S.SubSlice.Generator.Element == ${Element}, S.Index : BidirectionalIndexType, S.SubSlice.Index : BidirectionalIndexType, ${Element} : Equatable >( expected: ${Expected}, _ sliceable: S, _ stackTrace: SourceLocStack ) { // A `Sliceable` is a `CollectionType`. checkBidirectionalCollection(expected, sliceable, stackTrace.withCurrentLoc()) let expectedArray = _UnitTestArray(expected) var start = sliceable.startIndex for startNumericIndex in 0...expectedArray.count() { if start != sliceable.endIndex { ++start --start ++start --start } var end = start for endNumericIndex in startNumericIndex...expectedArray.count() { if end != sliceable.endIndex { ++end --end ++end --end } let expectedSlice = expectedArray[startNumericIndex..(x: C, _ n: Int) -> C.Index { return advance(x.startIndex, numericCast(n)) } public func nth(x: C, _ n: Int) -> C.Generator.Element { return x[nthIndex(x, n)] } public func checkRangeReplaceable< C: RangeReplaceableCollectionType, N: CollectionType where C.Generator.Element : Equatable, C.Generator.Element == N.Generator.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 = _UnitTestArray(makeCollection()) for (ix, i) in source.indices.enumerate() { for (jx_, j) in (i..( expected: Expected, _ actual: Actual, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { expectEqualSequence( expected, actual, { $0 == $1 }, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqualSequence< Expected : SequenceType, Actual : SequenceType, T : Equatable, U : Equatable where Expected.Generator.Element == Actual.Generator.Element, Expected.Generator.Element == (T, U) >( expected: Expected, _ actual: Actual, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { expectEqualSequence( expected, actual, { $0.0 == $1.0 && $0.1 == $1.1 }, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqualSequence< Expected: SequenceType, Actual: SequenceType where Expected.Generator.Element == Actual.Generator.Element >( expected: Expected, _ actual: Actual, _ sameValue: (Expected.Generator.Element, Expected.Generator.Element)->Bool, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { if !expected.elementsEqual(actual, isEquivalent: sameValue) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected elements: \"\(expected)\"") println("actual: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectEqualsUnordered< Expected : SequenceType, Actual : SequenceType where Expected.Generator.Element == Actual.Generator.Element >( expected: Expected, _ actual: Actual, _ compare: (Expected.Generator.Element, Expected.Generator.Element) -> ExpectedComparisonResult, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { let x: [Expected.Generator.Element] = sorted( Array(expected), compose(compare, { $0.isLT() })) let y: [Actual.Generator.Element] = sorted( Array(actual), compose(compare, { $0.isLT() })) expectEqualSequence( x, y, compose(compare, { $0.isEQ() }), stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqualsUnordered< Expected : SequenceType, Actual : SequenceType where Expected.Generator.Element == Actual.Generator.Element, Expected.Generator.Element : Comparable >( expected: Expected, _ actual: Actual, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { func compare( lhs: Expected.Generator.Element, rhs: Expected.Generator.Element ) -> ExpectedComparisonResult { if lhs < rhs { return .LT } if lhs == rhs { return .EQ } return .GT } expectEqualsUnordered( expected, actual, compare, stackTrace: stackTrace.map { $0.withCurrentLoc() }, file: file, line: line, collectMoreInfo: collectMoreInfo) } public func expectEqualsUnordered( expected: [T], _ actual: [T], stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { let x = sorted(expected) let y = sorted(actual) expectEqualSequence( x, y, { $0 == $1 }, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } /// 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 ].lexicographicalCompare( [ rhs.first, rhs.second ]) } public func expectEqualsUnordered( expected: [(T, T)], _ actual: [(T, T)], stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { let x = sorted(expected, { Pair($0.0, $0.1) < Pair($1.0, $1.1) }) let y = sorted(actual, { Pair($0.0, $0.1) < Pair($1.0, $1.1) }) expectEqualSequence( x, y, { Pair($0.0, $0.1) == Pair($1.0, $1.1) }, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) } /* This code crashes the compiler. If we could use this code, we wouldn't need the explicit overload for [(T, T)]. rdar://problem/19792730 rdar://problem/19792768 public func expectEqualsUnordered< Expected : SequenceType, Actual : SequenceType, T : Comparable where Expected.Generator.Element == Actual.Generator.Element, Expected.Generator.Element == (T, T) >( expected: Expected, _ actual: Actual, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { func comparePairLess(lhs: (T, T), rhs: (T, T)) -> Bool { return lexicographicalCompare([ lhs.0, lhs.1 ], [ rhs.0, rhs.1 ]) } let x: [(T, T)] = sorted(Array(expected), comparePairLess) let y: [(T, T)] = sorted(Array(actual), comparePairLess) func comparePairEquals(lhs: (T, T), rhs: (T, T)) -> Bool { return lhs.0 == rhs.0 && lhs.1 == rhs.1 } expectEqualSequence( x, y, comparePairEquals, stackTrace: stackTrace, file: file, line: line, collectMoreInfo: collectMoreInfo) }*/ 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: _UnitTestArray, _ actual: String, stackTrace: SourceLocStack? = nil, file: String = __FILE__, line: UWord = __LINE__, collectMoreInfo: (()->String)? = nil ) { let actualUnicodeScalars = _UnitTestArray(lazy(actual.unicodeScalars).map { $0.value }) if !expected.elementsEqual(actualUnicodeScalars) { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected elements: \"\(asHex(expected))\"") println("actual: \"\(asHex(actualUnicodeScalars))\"") if collectMoreInfo != nil { println(collectMoreInfo!()) } println() } } public func expectPrinted( expectedOneOf patterns: _UnitTestArray, _ object: T, file: StaticString = __FILE__, line: UWord = __LINE__ ) { let actual = String(object) if !patterns.contains(actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected: any of \(patterns.debugDescription)") println("actual: \"\(actual)\"") println() } } public func expectPrinted( expected: String, _ object: T, file: StaticString = __FILE__, line: UWord = __LINE__ ) { expectPrinted(expectedOneOf: [expected], object, file: file, line: line) } public func expectDebugPrinted( expectedOneOf patterns: _UnitTestArray, _ object: T, file: StaticString = __FILE__, line: UWord = __LINE__ ) { let actual = String(reflecting: object) if !patterns.contains(actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected: any of \(patterns.debugDescription)") println("actual: \"\(actual)\"") println() } } public func expectDebugPrinted( expected: String, _ object: T, file: StaticString = __FILE__, line: UWord = __LINE__ ) { expectDebugPrinted(expectedOneOf: [expected], object, file: file, line: line) } func compose(f: A -> B, _ g: B -> C) -> A -> C { return { a in return g(f(a)) } } /// State that is created every time a fresh generator is created with /// `MinimalSequence.generate()`. internal class _MinimalGeneratorPrivateState { internal init() {} internal var returnedNilCounter: Int = 0 } /// State shared by all generators of a MinimalSequence. internal class _MinimalGeneratorSharedState { internal init(_ data: [T]) { self.data = data } internal let data: [T] internal var i: Int = 0 internal var underestimatedCount: Int = 0 } //===----------------------------------------------------------------------===// // MinimalGenerator //===----------------------------------------------------------------------===// /// A GeneratorType that implements the protocol contract in the most /// narrow way possible. /// /// This generator will return `nil` only once. public struct MinimalGenerator : GeneratorType { public init(_ s: S) { self._sharedState = _MinimalGeneratorSharedState(Array(s)) } public init(_ data: [T]) { self._sharedState = _MinimalGeneratorSharedState(data) } internal init(_ _sharedState: _MinimalGeneratorSharedState) { self._sharedState = _sharedState } public func next() -> T? { if _sharedState.i == _sharedState.data.count() { if isConsumed { expectUnreachable() { "next() was called on a consumed generator" } } ++_privateState.returnedNilCounter return nil } return _sharedState.data[_sharedState.i++] } public var isConsumed: Bool { return returnedNilCounter >= 1 } public var returnedNilCounter: Int { return _privateState.returnedNilCounter } internal let _privateState: _MinimalGeneratorPrivateState = _MinimalGeneratorPrivateState() internal let _sharedState: _MinimalGeneratorSharedState } //===----------------------------------------------------------------------===// // MinimalSequence //===----------------------------------------------------------------------===// public enum UnderestimateCountBehavior { /// Return the actual number of elements. case Precise /// Return the actual number of elements divided by 2. case Half /// Return an overestimated count. Useful to test how algorithms reserve /// memory. case Overestimate /// Return the provided value. case Value(Int) } /// A SequenceType that implements the protocol contract in the most /// narrow way possible. /// /// This sequence is consumed when its generator is advanced. public struct MinimalSequence : SequenceType { public init( _ s: S, underestimatedCount: UnderestimateCountBehavior = .Value(0) ) { let data = Array(s) self._sharedState = _MinimalGeneratorSharedState(data) switch underestimatedCount { case .Precise: self._sharedState.underestimatedCount = data.count() case .Half: self._sharedState.underestimatedCount = data.count() / 2 case .Overestimate: self._sharedState.underestimatedCount = data.count() * 3 + 5 case .Value(let count): self._sharedState.underestimatedCount = count } } public func generate() -> MinimalGenerator { return MinimalGenerator(_sharedState) } public func underestimateCount() -> Int { return max(0, self._sharedState.underestimatedCount - self._sharedState.i) } internal let _sharedState: _MinimalGeneratorSharedState } //===----------------------------------------------------------------------===// // MinimalForwardIndex //===----------------------------------------------------------------------===// % for Distance in [ '', 'Int32' ]: public struct MinimalForward${Distance}Index : ForwardIndexType { % if Distance != '': typealias Distance = ${Distance} % end public init(position: Int, endIndex: Int) { self.position = position self.endIndex = endIndex } public init(position: Int, startIndex _: Int, endIndex: Int) { self.position = position self.endIndex = endIndex } public func successor() -> MinimalForward${Distance}Index { expectNotEqual(endIndex, position) return MinimalForward${Distance}Index( position: position + 1, endIndex: endIndex) } public let position: Int public let endIndex: Int } public func == ( lhs: MinimalForward${Distance}Index, rhs: MinimalForward${Distance}Index ) -> Bool { return lhs.position == rhs.position } % end //===----------------------------------------------------------------------===// // MinimalBidirectionalIndex //===----------------------------------------------------------------------===// public struct MinimalBidirectionalIndex : BidirectionalIndexType { public init(position: Int, startIndex: Int, endIndex: Int) { self.position = position self.startIndex = startIndex self.endIndex = endIndex } public func successor() -> MinimalBidirectionalIndex { expectNotEqual(endIndex, position) return MinimalBidirectionalIndex( position: position + 1, startIndex: startIndex, endIndex: endIndex) } public func predecessor() -> MinimalBidirectionalIndex { expectNotEqual(startIndex, position) return MinimalBidirectionalIndex( position: position - 1, startIndex: startIndex, endIndex: endIndex) } public let position: Int public let startIndex: Int public let endIndex: Int } public func == ( lhs: MinimalBidirectionalIndex, rhs: MinimalBidirectionalIndex ) -> Bool { return lhs.position == rhs.position } //===----------------------------------------------------------------------===// // MinimalRandomAccessIndex //===----------------------------------------------------------------------===// public struct MinimalRandomAccessIndex : RandomAccessIndexType { public init(position: Int, startIndex: Int, endIndex: Int) { self.position = position self.startIndex = startIndex self.endIndex = endIndex } public func successor() -> MinimalRandomAccessIndex { expectNotEqual(endIndex, position) return MinimalRandomAccessIndex( position: position + 1, startIndex: startIndex, endIndex: endIndex) } public func predecessor() -> MinimalRandomAccessIndex { expectNotEqual(startIndex, position) return MinimalRandomAccessIndex( position: position - 1, startIndex: startIndex, endIndex: endIndex) } public func distanceTo(other: MinimalRandomAccessIndex) -> Int { return other.position - position } public func advancedBy(n: Int) -> MinimalRandomAccessIndex { expectNotEqual(endIndex, position) let newPosition = position + n expectLE(startIndex, newPosition) expectGE(endIndex, newPosition) return MinimalRandomAccessIndex( position: newPosition, startIndex: startIndex, endIndex: endIndex) } public let position: Int public let startIndex: Int public let endIndex: Int } public func == ( lhs: MinimalRandomAccessIndex, rhs: MinimalRandomAccessIndex ) -> Bool { return lhs.position == rhs.position } //===----------------------------------------------------------------------===// // Minimal***Collection //===----------------------------------------------------------------------===// % for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: % for mutable in [ False, True ]: // This comment is a workaround for gyb miscompiles nested loops % Self = 'Minimal%s%sCollection' % ('Mutable' if mutable else '', traversal) % Index = 'Minimal%sIndex' % traversal /// A minimal implementation of `CollectionType` with extra checks. public struct ${Self} : ${'MutableCollectionType' if mutable else 'CollectionType'} { public init( _ s: S, underestimatedCount: UnderestimateCountBehavior = .Value(0) ) { self._elements = Array(s) switch underestimatedCount { case .Precise: self.underestimatedCount = _elements.count() case .Half: self.underestimatedCount = _elements.count() / 2 case .Overestimate: self.underestimatedCount = _elements.count() * 3 + 5 case .Value(let count): self.underestimatedCount = count } } public func generate() -> MinimalGenerator { return MinimalGenerator(_elements) } public var startIndex: ${Index} { return ${Index}( position: 0, startIndex: 0, endIndex: _elements.endIndex) } public var endIndex: ${Index} { return ${Index}( position: _elements.endIndex, startIndex: 0, endIndex: _elements.endIndex) } public subscript(i: ${Index}) -> T { get { return _elements[i.position] } % if mutable: set { _elements[i.position] = newValue } % end } public func underestimateCount() -> Int { return underestimatedCount } public var underestimatedCount: Int internal var _elements: [T] } % end % end //===----------------------------------------------------------------------===// // Minimal***RangeReplaceableCollectionType //===----------------------------------------------------------------------===// %for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]: % Self = 'Minimal%sRangeReplaceableCollectionType' % traversal % Index = 'Minimal%sIndex' % traversal /// A minimal implementation of `RangeReplaceableCollectionType` with extra /// checks. public struct ${Self} : RangeReplaceableCollectionType { public init( _ s: S, underestimatedCount: UnderestimateCountBehavior = .Value(0) ) { self.elements = Array(s) switch underestimatedCount { case .Precise: self.underestimatedCount = elements.count() case .Half: self.underestimatedCount = elements.count() / 2 case .Overestimate: self.underestimatedCount = elements.count() * 3 + 5 case .Value(let count): self.underestimatedCount = count } } public init() { self.underestimatedCount = 0 self.elements = [] } public func generate() -> MinimalGenerator { return MinimalGenerator(elements) } public func underestimateCount() -> Int { return underestimatedCount } public var startIndex: ${Index} { return ${Index}( position: 0, startIndex: 0, endIndex: elements.endIndex) } public var endIndex: ${Index} { return ${Index}( position: elements.endIndex, startIndex: 0, endIndex: elements.endIndex) } public subscript(i: ${Index}) -> T { return elements[i.position] } public mutating func reserveCapacity(n: Int) { elements.reserveCapacity(n) reservedCapacity = max(reservedCapacity, n) } public mutating func append(x: T) { elements.append(x) } public mutating func extend< S : SequenceType where S.Generator.Element == T >(newElements: S) { elements.extend(newElements) } public mutating func replaceRange< C : CollectionType where C.Generator.Element == T >( subRange: Range<${Index}>, with newElements: C ) { elements.replaceRange( subRange.startIndex.position..(newElements: S, atIndex i: ${Index}) { elements.splice(newElements, atIndex: i.position) } public mutating func removeAtIndex(i: ${Index}) -> T { return elements.removeAtIndex(i.position) } public mutating func removeRange(subRange: Range<${Index}>) { elements.removeRange( subRange.startIndex.position.. { 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 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 return value.hashValue } } public func == ( lhs: ${Self}, rhs: ${Self} ) -> Bool { ++${Self}.timesEqualEqualWasCalled return lhs.value == rhs.value } % end /// 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: Int = 0 public static var timesLessWasCalled: 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: MinimalComparableValue, rhs: MinimalComparableValue ) -> Bool { ++MinimalComparableValue.timesEqualEqualWasCalled return lhs.value == rhs.value } public func < ( lhs: MinimalComparableValue, rhs: MinimalComparableValue ) -> Bool { ++MinimalComparableValue.timesLessWasCalled return lhs.value < rhs.value } // ${'Local Variables'}: // eval: (read-only-mode 1) // End: