//===--- 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 Darwin public struct SourceLoc { let file: String let line: UWord 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: [SourceLoc] = [] public init() {} 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 withCurrentLoc( file: String = __FILE__, line: UWord = __LINE__ ) -> SourceLocStack { return with(SourceLoc(file, line)) } } func _printStackTrace(stackTrace: SourceLocStack?) { if let s = stackTrace { println("stacktrace:") for i in 0..( expected: T, actual: T, stackTrace: SourceLocStack? = nil, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { expectEqual(expected, actual, {$0 == $1}, stackTrace: stackTrace, collectMoreInfo, file: file, line: line) } public func expectEqual( expected: T, actual: T, equal: (T,T)->Bool, stackTrace: SourceLocStack? = nil, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { 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__ ) { if expected == actual { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("unexpected value: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") 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?, 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() } } // Array is not Equatable if T is. Provide additional overloads. // Same for Dictionary. %for (Generic, EquatableType) in [ % ('', 'ContiguousArray'), % ('', 'Slice'), % ('', 'Array'), % ('', 'Dictionary'), % ('', 'T')]: public func expectEqual${Generic}( expected: ${EquatableType}, actual: ${EquatableType}, stackTrace: SourceLocStack? = nil, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { expectEqual( expected, actual, // FIXME: Simpler closures don't work here due to // and { (x: ${EquatableType}, y: ${EquatableType})->Bool in x == y }, stackTrace: stackTrace, collectMoreInfo, file: file, line: line) } func _expectNotEqual${Generic}( expected: ${EquatableType}, actual: ${EquatableType}, file: String = __FILE__, line: UWord = __LINE__ ) { if expected == actual { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("unexpected value: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))") println() } } %end %for ComparableType in ['Int']: public func expectLE( expected: ${ComparableType}, actual: ${ComparableType}, file: String = __FILE__, line: UWord = __LINE__ ) { if !(expected <= actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected: \"\(expected)\"") println("actual: \"\(actual)\"") println() } } public func expectGE( expected: ${ComparableType}, actual: ${ComparableType}, file: String = __FILE__, line: UWord = __LINE__ ) { if !(expected >= actual) { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected: \"\(expected)\"") println("actual: \"\(actual)\"") println() } } %end public struct AssertionResult : Printable, 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) } %for BoolType in ['Bool', 'AssertionResult']: public func expectTrue( actual: ${BoolType}, stackTrace: SourceLocStack? = nil, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { 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, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { 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__ ) { if value != nil { _anyExpectFailed = true println("check failed at \(file), line \(line)") _printStackTrace(stackTrace) println("expected optional to be empty") println("actual: \"\(value)\"") println() } } public func expectNotEmpty( value: Optional, file: String = __FILE__, line: UWord = __LINE__ ) { if value == nil { _anyExpectFailed = true println("check failed at \(file), line \(line)") println("expected optional to be non-empty") println() } } public func expectCrashLater() { println("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed)") var stderr = _Stderr() println("\(_stdlibUnittestStreamPrefix);expectCrash", &stderr) _seenExpectCrash = true } func _defaultTestCaseFailedCallback() { abort() } var _testCaseFailedCallback: () -> () = _defaultTestCaseFailedCallback public func _setTestCaseFailedCallback(callback: () -> ()) { _testCaseFailedCallback = callback } var _runTestsInProcess: Bool { return contains(Process.arguments, "--stdlib-unittest-in-process") } var _isChildProcess: Bool { return contains(Process.arguments, "--stdlib-unittest-run-child") } func _stdlib_getline() -> String? { var result = [UInt8]() while true { let c = getchar() if c == EOF { return nil } if c == CInt(UnicodeScalar("\n").value) { return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result) } result.append(UInt8(c)) } } struct _FDInputStream { let fd: CInt var isEOF: Bool = false var _buffer = ContiguousArray(count: 256, repeatedValue: 0) var _bufferUsed: Int = 0 init(fd: CInt) { self.fd = fd } mutating func getline() -> String? { if let newlineIndex = find(_buffer[0..<_bufferUsed], UInt8(UnicodeScalar("\n").value)) { var result = String._fromWellFormedCodeUnitSequence( UTF8.self, input: _buffer[0.. 0 { var result = String._fromWellFormedCodeUnitSequence( UTF8.self, input: _buffer[0..<_bufferUsed]) _buffer.removeAll() _bufferUsed = 0 return result } return nil } mutating func read() { let minFree = 128 var bufferFree = _buffer.count - _bufferUsed if bufferFree < minFree { _buffer.reserveCapacity(minFree - bufferFree) while bufferFree < minFree { _buffer.append(0) ++bufferFree } } let readResult: ssize_t = _buffer.withUnsafeMutableBufferPointer { (_buffer) in return Darwin.read( self.fd, _buffer.baseAddress + self._bufferUsed, size_t(bufferFree)) } if readResult == 0 { isEOF = true return } if readResult < 0 { fatalError("read() returned error") } _bufferUsed += readResult } } func _printDebuggingAdvice() { println("To debug, run:") println("$ \(Process.arguments[0]) --stdlib-unittest-in-process") } var _allTestCases: [TestCase] = [] var _testCaseNameToIndex: [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 testCaseName = parts[0] let testName = parts[1] let testCase = _allTestCases[_testCaseNameToIndex[testCaseName]!] let test = testCase._getTestByName(testName) _anyExpectFailed = false test.code() println("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed)") var stderr = _Stderr() println("\(_stdlibUnittestStreamPrefix);end", &stderr) } } struct _ParentProcess { var _pid: pid_t = -1 var _childStdinFD: CInt = -1 var _childStdoutFD: CInt = -1 var _childStderrFD: CInt = -1 mutating func _spawnChild() { (_pid, _childStdinFD, _childStdoutFD, _childStderrFD) = spawnChild([ "--stdlib-unittest-run-child" ]) } mutating func _waitForChild() -> ProcessTerminationStatus { let status = posixWaitpid(_pid) _pid = -1 if close(_childStdinFD) != 0 { preconditionFailure("close() failed") } if close(_childStdoutFD) != 0 { preconditionFailure("close() failed") } if close(_childStderrFD) != 0 { preconditionFailure("close() failed") } return status } /// Returns the values of the corresponding variables in the child process. mutating func _runTestInChild(testCaseName: String, _ testName: String) -> (anyExpectFailed: Bool, seenExpectCrash: Bool, status: ProcessTerminationStatus?, crashStdout: [String], crashStderr: [String]) { if _pid <= 0 { _spawnChild() } var childStdin = _FDOutputStream(fd: _childStdinFD) var childStdout = _FDInputStream(fd: _childStdoutFD) var childStderr = _FDInputStream(fd: _childStderrFD) println("\(testCaseName);\(testName)", &childStdin) 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(_childStdoutFD) errorfds.set(_childStdoutFD) } if !childStderr.isEOF { readfds.set(_childStderrFD) errorfds.set(_childStderrFD) } let ret = _stdlib_select(&readfds, &writefds, &errorfds, nil) if ret <= 0 { fatalError("select() returned an error") } if readfds.isset(_childStdoutFD) || errorfds.isset(_childStdoutFD) { childStdout.read() while var line = childStdout.getline() { if let index = findSubstring(line, _stdlibUnittestStreamPrefix) { let controlMessage = line[index..>> \(line)") } continue } if readfds.isset(_childStderrFD) || errorfds.isset(_childStderrFD) { childStderr.read() while var line = childStderr.getline() { if let index = findSubstring(line, _stdlibUnittestStreamPrefix) { let controlMessage = line[index..>> \(line)") } continue } } if stdoutEnd && stderrEnd { return ( anyExpectFailedInChild, stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, nil, capturedCrashStdout, capturedCrashStderr) } // We reached EOF on stdout and stderr, it looks like child crashed (of // course it could have closed the file descriptors, but we assume it did // not). let status = _waitForChild() return ( anyExpectFailedInChild, stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status, capturedCrashStdout, capturedCrashStderr) } mutating func run() { for testCase in _allTestCases { var uxpassedTests = [String]() var failedTests = [String]() var skippedTests = [String]() for t in testCase._tests { let fullTestName = "\(testCase.name).\(t.name)" 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 = [String]() var crashStderr = [String]() if _runTestsInProcess { _anyExpectFailed = false t.code() } else { (_anyExpectFailed, expectCrash, childTerminationStatus, crashStdout, crashStderr) = _runTestInChild(testCase.name, 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 default: preconditionFailure("unreachable") } if testPassed { if let crashOutputMatches = t.crashOutputMatches { // If we still think that the test passed, check if the crash // output matches our expectations. var found = false for s in crashStdout + crashStderr { if findSubstring(s, crashOutputMatches) != nil { found = true break } } if !found { println("did not find expected string \(crashOutputMatches.debugDescription)") } testPassed = found } } // 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)") default: preconditionFailure("unreachable") } } if !uxpassedTests.isEmpty || !failedTests.isEmpty { println("\(testCase.name): Some tests failed, aborting") println("UXPASS: \(uxpassedTests)") println("FAIL: \(failedTests)") println("SKIP: \(skippedTests)") _printDebuggingAdvice() _testCaseFailedCallback() } else { println("\(testCase.name): All tests passed") } } } } public func runAllTests() { if _isChildProcess { _childProcess() } else { var parent = _ParentProcess() parent.run() } } public class TestCase { public init(_ name: String) { self.name = name _precondition( _testNameToIndex[name] == nil, "test case with the same name already exists") _allTestCases.append(self) _testCaseNameToIndex[name] = _allTestCases.count - 1 } public func test(name: String, _ testFunction: () -> ()) { _TestBuilder(testCase: self, name: name).code(testFunction) } public func test(name: String) -> _TestBuilder { return _TestBuilder(testCase: self, name: name) } func _getTestByName(name: String) -> _Test { return _tests[_testNameToIndex[name]!] } struct _Test { let name: String let xfail: [TestRunPredicate] let skip: [TestRunPredicate] let crashOutputMatches: String? let code: () -> () func getActiveXFailPredicates() -> [TestRunPredicate] { return xfail.filter { $0.evaluate() } } func getActiveSkipPredicates() -> [TestRunPredicate] { return skip.filter { $0.evaluate() } } } public struct _TestBuilder { let _testCase: TestCase var _name: String var _data: _Data = _Data() class _Data { var _xfail: [TestRunPredicate] = [] var _skip: [TestRunPredicate] = [] var _crashOutputMatches: String? } init(testCase: TestCase, name: String) { _testCase = testCase _name = name } public func xfail(predicates: TestRunPredicate) -> _TestBuilder { _data._xfail.append(predicates) return self } public func skip(predicates: TestRunPredicate) -> _TestBuilder { _data._skip.append(predicates) return self } public func crashOutputMatches(string: String) -> _TestBuilder { _data._crashOutputMatches = string return self } public func code(testFunction: () -> ()) { _testCase._tests.append(_Test( name: _name, xfail: _data._xfail, skip: _data._skip, crashOutputMatches: _data._crashOutputMatches, code: testFunction)) _testCase._testNameToIndex[_name] = _testCase._tests.count - 1 } } var name: String var _tests: [_Test] = [] /// Maps test name to index in `_tests`. var _testNameToIndex: [String : Int] = [:] } @asmname("swift_stdlib_getSystemVersionPlistProperty") func _stdlib_getSystemVersionPlistPropertyImpl( propertyName: UnsafePointer) -> UnsafePointer func _stdlib_getSystemVersionPlistProperty(propertyName: String) -> String? { return String.fromCString( _stdlib_getSystemVersionPlistPropertyImpl(propertyName)) } public enum OSVersion : Printable { case OSX(major: Int, minor: Int, bugFix: Int) case iOS(major: Int, minor: Int, bugFix: Int) case iOSSimulator 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" } } } func _parseDottedVersion(s: String) -> [Int] { return s._split(".").map { $0.toInt()! } } 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 #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 : Printable { 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) 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))" } } 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 contains(minorRange, 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 contains(bugFixRange, 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 contains(minorRange, 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 contains(bugFixRange, runningBugFix) default: return false } case iOSSimulatorAny: switch _getRunningOSVersion() { case .iOSSimulator: return true default: return false } } } } // // Helpers that verify invariants of various stdlib types. // 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) expectEqual( !expectedEqual, lhs != rhs, stackTrace: stackTrace, 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) } } public func checkHashable( expectedEqual: Bool, lhs: T, rhs: T, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { checkHashable( expectedEqual, lhs, rhs, SourceLocStack(SourceLoc(file, line)), 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 } } } public func checkComparable( expected: ExpectedComparisonResult, lhs: T, rhs: T, stackTrace: SourceLocStack ) { expectEqual(expected.isLT(), lhs < rhs, stackTrace: stackTrace) expectEqual(expected.isLE(), lhs <= rhs, stackTrace: stackTrace) expectEqual(expected.isGE(), lhs >= rhs, stackTrace: stackTrace) expectEqual(expected.isGT(), lhs > rhs, stackTrace: stackTrace) } public func checkComparable( expected: ExpectedComparisonResult, lhs: T, rhs: T, file: String = __FILE__, line: UWord = __LINE__ ) { checkComparable(expected, lhs, rhs, SourceLocStack(SourceLoc(file, line))) } public func checkGenerator< Element : Equatable, G : GeneratorType where G.Element == Element>( expected: [Element], generator: G, stackTrace: SourceLocStack) { // Copying a `GeneratorType` is allowed. var mutableGen = generator var actual: [Element] = [] while let e = mutableGen.next() { actual.append(e) } expectEqual(expected, actual, stackTrace: stackTrace.withCurrentLoc()) // Having returned `.None` once, a `GeneratorType` should not generate more // elements. for i in 0..<10 { expectEmpty(mutableGen.next(), stackTrace: stackTrace.withCurrentLoc()) } } public func checkSequence< Element : Equatable, S : SequenceType where S.Generator.Element == Element>( expected: [Element], sequence: S, stackTrace: SourceLocStack) { checkGenerator(expected, sequence.generate(), stackTrace.withCurrentLoc()) expectGE(expected.count, underestimateCount(sequence)) } public func checkCollection< Element : Equatable, C : CollectionType where C.Generator.Element == Element>( expected: [Element], collection: C, stackTrace: SourceLocStack) { // A `CollectionType` is a multi-pass `SequenceType`. for i in 0..<3 { checkSequence(expected, collection, stackTrace.withCurrentLoc()) } expectEqual(expected.count.toIntMax(), countElements(collection).toIntMax(), stackTrace: stackTrace.withCurrentLoc()) for i in 0..<3 { let startIndex = collection.startIndex let endIndex = collection.endIndex var actual: [Element] = [] var index = collection.startIndex while index != collection.endIndex { // Iteration should not change `startIndex` or `endIndex`. expectEqual(startIndex, collection.startIndex) expectEqual(endIndex, collection.endIndex) actual.append(collection[index]) ++index } expectEqual(expected, actual, stackTrace: stackTrace.withCurrentLoc()) } } public func checkSliceableWithBidirectionalIndex< Element : Equatable, S : Sliceable where S.Generator.Element == Element, S.SubSlice.Generator.Element == Element, S.Index : BidirectionalIndexType>( expected: [Element], sliceable: S, stackTrace: SourceLocStack) { // A `Sliceable` is a `CollectionType`. checkCollection(expected, sliceable, stackTrace.withCurrentLoc()) var start = sliceable.startIndex for startNumericIndex in 0...expected.count { if start != sliceable.endIndex { ++start --start ++start --start } var end = start for endNumericIndex in startNumericIndex...expected.count { if end != sliceable.endIndex { ++end --end ++end --end } let expectedSlice: [Element] = Array(expected[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. var source = ContiguousArray() for x in makeCollection() { source.append(x) } for (ix, i) in enumerate(indices(source)) { for (jx_, j) in enumerate(i..( expected: Expected, actual: Actual, stackTrace: SourceLocStack? = nil, _ collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { expectEqualSequence( expected, actual, { $0 == $1 }, stackTrace: stackTrace, collectMoreInfo: collectMoreInfo, file: file, line: line) } 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, collectMoreInfo: (()->String)? = nil, file: String = __FILE__, line: UWord = __LINE__ ) { if !equal(expected, actual, 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() } } // ${'Local Variables'}: // eval: (read-only-mode 1) // End: