Files
swift-mirror/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
Chris Lattner 20f8f09ea8 Land: <rdar://problem/19382905> improve 'if let' to support refutable patterns and untie it from optionals
This changes 'if let' conditions to take general refutable patterns, instead of
taking a irrefutable pattern and implicitly matching against an optional.

Where before you might have written:
  if let x = foo() {

you now need to write:
  if let x? = foo() {
    
The upshot of this is that you can write anything in an 'if let' that you can
write in a 'case let' in a switch statement, which is pretty general.

To aid with migration, this special cases certain really common patterns like
the above (and any other irrefutable cases, like "if let (a,b) = foo()", and
tells you where to insert the ?.  It also special cases type annotations like
"if let x : AnyObject = " since they are no longer allowed.

For transitional purposes, I have intentionally downgraded the most common
diagnostic into a warning instead of an error.  This means that you'll get:

t.swift:26:10: warning: condition requires a refutable pattern match; did you mean to match an optional?
if let a = f() {
       ^
        ?

I think this is important to stage in, because this is a pretty significant
source breaking change and not everyone internally may want to deal with it
at the same time.  I filed 20166013 to remember to upgrade this to an error.

In addition to being a nice user feature, this is a nice cleanup of the guts
of the compiler, since it eliminates the "isConditional()" bit from
PatternBindingDecl, along with the special case logic in the compiler to handle
it (which variously added and removed Optional around these things).




Swift SVN r26150
2015-03-15 07:06:22 +00:00

2065 lines
59 KiB
Swift

//===--- 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)
import Darwin
#elseif os(Linux)
import Glibc
#endif
#if _runtime(_ObjC)
import ObjectiveC
#endif
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: _UnitTestArray<SourceLoc>
public init() {
locs = []
}
public init(_ loc: SourceLoc) {
locs = [ loc ]
}
init(_locs: _UnitTestArray<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..<s.locs.count {
let loc = s.locs[s.locs.count - i - 1]
let comment = (loc.comment != nil) ? " ; \(loc.comment!)" : ""
println(" #\(i): \(loc.file):\(loc.line)\(comment)")
}
}
}
// FIXME: these variables should be atomic, since multiple threads can call
// `expect*()` functions.
var _anyExpectFailed = false
var _seenExpectCrash = false
public func expectEqual<T : Equatable>(
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<T: Equatable, U: Equatable>(
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<T>(
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<T : Equatable>(
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:
// <rdar://problem/17015923> Array->NSArray implicit conversion insanity
public func expectOptionalEqual<T : Equatable>(
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()
}
}
public func expectEqual<T : Equatable>(
expected: T?, actual: T?,
file: String = __FILE__, line: UWord = __LINE__
) {
if (actual == nil) != (expected == nil)
|| 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<T> is not Equatable if T is. Provide additional overloads.
// Same for Dictionary.
%for (Generic, EquatableType) in [
% ('<T : Equatable>', 'ContiguousArray<T>'),
% ('<T : Equatable>', '_UnitTestArray<T>'),
% ('<T : Equatable>', 'ArraySlice<T>'),
% ('<T : Equatable>', 'Array<T>'),
% ('<T, U : Equatable>', 'Dictionary<T, U>'),
% ('<T : ForwardIndexType>', 'T')]:
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
// <rdar://problem/17716712> and <rdar://problem/17717618>
{ (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
// <rdar://problem/17716712> and <rdar://problem/17717618>
{ (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__
) {
if expected == actual {
_anyExpectFailed = true
println("check failed at \(file), line \(line)")
println("unexpected value: \"\(actual)\" (of type \(_stdlib_getDemangledTypeName(actual)))")
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 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 func expectType<T>(_: T.Type, inout x: T) {}
public func isSequenceType<X : SequenceType>(x: X) -> X { return x }
public func expectIsBooleanType<X : BooleanType>(inout x: X) -> X { return x }
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)
}
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()
}
%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<T>(
value: Optional<T>,
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<T>(
value: Optional<T>,
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 _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<UInt8>()
while true {
let c = getchar()
if c == EOF {
if result.count == 0 {
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<TestSuite> = []
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<String>, crashStderr: _UnitTestArray<String>) {
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<String>()
var capturedCrashStderr = _UnitTestArray<String>()
var anyExpectFailedInChild = false
while !((_childStdout.isEOF && _childStderr.isEOF) ||
(stdoutEnd && stderrEnd)) {
readfds.zero()
errorfds.zero()
if !_childStdout.isEOF {
readfds.set(_childStdout.fd)
errorfds.set(_childStdout.fd)
}
if !_childStderr.isEOF {
readfds.set(_childStderr.fd)
errorfds.set(_childStderr.fd)
}
var ret: CInt
do {
ret = _stdlib_select(&readfds, &writefds, &errorfds, nil)
} while ret == -1 && errno == EINTR
if ret <= 0 {
fatalError("select() returned an error")
}
if readfds.isset(_childStdout.fd) || errorfds.isset(_childStdout.fd) {
_childStdout.read()
while var line? = _childStdout.getline() {
if let index? = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage = line[index..<line.endIndex]._split(";")
switch controlMessage[1] {
case "expectCrash":
stdoutSeenCrashDelimiter = true
anyExpectFailedInChild = controlMessage[2] == "true"
case "end":
stdoutEnd = true
anyExpectFailedInChild = controlMessage[2] == "true"
default:
fatalError("unexpected message")
}
line = line[line.startIndex..<index]
if line.isEmpty {
continue
}
}
if stdoutSeenCrashDelimiter {
capturedCrashStdout.append(line)
}
println("out>>> \(line)")
}
continue
}
if readfds.isset(_childStderr.fd) || errorfds.isset(_childStderr.fd) {
_childStderr.read()
while var line? = _childStderr.getline() {
if let index? = findSubstring(line, _stdlibUnittestStreamPrefix) {
let controlMessage = line[index..<line.endIndex]._split(";")
switch controlMessage[1] {
case "expectCrash":
stderrSeenCrashDelimiter = true
case "end":
stderrEnd = true
default:
fatalError("unexpected message")
}
line = line[line.startIndex..<index]
if line.isEmpty {
continue
}
}
if stderrSeenCrashDelimiter {
capturedCrashStderr.append(line)
}
println("err>>> \(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<String>()
var failedTests = _UnitTestArray<String>()
var skippedTests = _UnitTestArray<String>()
for t in testSuite._tests {
let fullTestName = "\(testSuite.name).\(t.name)"
if let filter? = _filter {
if 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<String>()
var crashStderr = _UnitTestArray<String>()
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
default:
preconditionFailure("unreachable")
}
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)")
default:
preconditionFailure("unreachable")
}
}
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() {
#if _runtime(ObjC)
autoreleasepool {
_stdlib_initializeReturnAutoreleased()
}
#endif
let _isChildProcess: Bool =
contains(Process.arguments, "--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<TestRunPredicate>
let skip: _UnitTestArray<TestRunPredicate>
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<TestRunPredicate> {
return xfail.filter { $0.evaluate() }
}
func getActiveSkipPredicates() -> _UnitTestArray<TestRunPredicate> {
return skip.filter { $0.evaluate() }
}
}
public struct _TestBuilder {
let _testSuite: TestSuite
var _name: String
var _data: _Data = _Data()
class _Data {
var _xfail: _UnitTestArray<TestRunPredicate> = []
var _skip: _UnitTestArray<TestRunPredicate> = []
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)
@asmname("swift_stdlib_getSystemVersionPlistProperty")
func _stdlib_getSystemVersionPlistPropertyImpl(
propertyName: UnsafePointer<CChar>) -> UnsafePointer<CChar>
func _stdlib_getSystemVersionPlistProperty(propertyName: String) -> String? {
return String.fromCString(
_stdlib_getSystemVersionPlistPropertyImpl(propertyName))
}
#endif
public enum OSVersion : Printable {
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<Int> {
return _UnitTestArray(lazy(s._split(".")).map { $0.toInt()! })
}
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 : 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<Int>, reason: String)
case OSXBugFix(Int, Int, Int, reason: String)
case OSXBugFixRange(Int, Int, Range<Int>, reason: String)
case iOSAny(/*reason:*/ String)
case iOSMajor(Int, reason: String)
case iOSMinor(Int, Int, reason: String)
case iOSMinorRange(Int, Range<Int>, reason: String)
case iOSBugFix(Int, Int, Int, reason: String)
case iOSBugFixRange(Int, Int, Range<Int>, reason: String)
case iOSSimulatorAny(/*reason:*/ String)
case 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 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
}
case LinuxAny:
switch _getRunningOSVersion() {
case .Linux:
return true
default:
return false
}
}
}
}
//
// Helpers that verify invariants of various stdlib types.
//
public func checkEquatable<T : Equatable>(
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<T : Equatable>(
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<T : Hashable>(
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<T : Hashable>(
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 : Printable {
public var description: String {
switch self {
case .LT:
return "<"
case .EQ:
return "=="
case .GT:
return ">"
}
}
}
public func checkComparable<T : Comparable>(
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<T : Comparable>(
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)
}
// 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<Element>')):
public func checkGenerator<
G : GeneratorType, ${genericParam}
where ${Element} == G.Element, ${Element} : Equatable
>(
expected: ${Expected},
generator: G, stackTrace: SourceLocStack
) {
// Copying a `GeneratorType` is allowed.
var mutableGen = generator
var actual: _UnitTestArray<${Element}> = []
while let e? = mutableGen.next() {
actual.append(e)
}
expectEqualSequence(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<
${genericParam}, S : SequenceType
where S.Generator.Element == ${Element}, ${Element} : Equatable
>(
expected: ${Expected},
sequence: S, stackTrace: SourceLocStack
) {
let expectedCount: Int = numericCast(count(expected))
checkGenerator(expected, sequence.generate(), stackTrace.withCurrentLoc())
expectGE(expectedCount, underestimateCount(sequence))
}
public func checkCollection<
${genericParam}, C : CollectionType
where C.Generator.Element == ${Element}, ${Element} : Equatable
>(
expected: ${Expected},
collection: C, stackTrace: SourceLocStack
) {
// A `CollectionType` is a multi-pass `SequenceType`.
for i in 0..<3 {
checkSequence(expected, collection, stackTrace.withCurrentLoc())
}
expectEqual(count(expected).toIntMax(), count(collection).toIntMax(),
stackTrace: stackTrace.withCurrentLoc())
for i in 0..<3 {
let startIndex = collection.startIndex
let endIndex = collection.endIndex
var actual: _UnitTestArray<${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
}
expectEqualSequence(
expected, actual, stackTrace: stackTrace.withCurrentLoc())
}
}
public func checkSliceableWithBidirectionalIndex<
${genericParam}, S : Sliceable
where S.Generator.Element == ${Element},
S.SubSlice.Generator.Element == ${Element},
S.Index : BidirectionalIndexType,
${Element} : Equatable
>(
expected: ${Expected},
sliceable: S, stackTrace: SourceLocStack) {
// A `Sliceable` is a `CollectionType`.
checkCollection(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..<endNumericIndex]
let slice = sliceable[start..<end]
checkCollection(expectedSlice, slice, stackTrace.withCurrentLoc())
if end != sliceable.endIndex {
++end
}
}
if start != sliceable.endIndex {
++start
}
}
}
% end
public func nthIndex<C: CollectionType>(x: C, n: Int) -> C.Index {
return advance(x.startIndex, numericCast(n))
}
public func nth<C: CollectionType>(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<A.Generator.Element>(makeCollection())
for (ix, i) in enumerate(indices(source)) {
for (jx_, j) in enumerate(i..<source.endIndex) {
let jx = jx_ + ix
let oldCount = jx - ix
for newCount in 0..<(2 * oldCount) {
let newValues = makeNewValues(newCount)
func reportFailure(inout a: A, message: String) {
println("\(message) when replacing indices \(ix)...\(jx)")
println(" in \(_UnitTestArray(source)) with \(_UnitTestArray(newValues))")
println(" yielding \(_UnitTestArray(a))")
println("====================================")
expectTrue(false)
}
var a = makeCollection()
a.replaceRange(nthIndex(a, ix)..<nthIndex(a, jx), with: newValues)
let growth = newCount - oldCount
let expectedCount = source.count + growth
let actualCount = numericCast(count(a)) as Int
if actualCount != expectedCount {
reportFailure(
&a, "\(actualCount) != expected count \(expectedCount)")
}
for (kx, k) in enumerate(indices(a)) {
let expectedValue = kx < ix ? nth(source, kx)
: kx < jx + growth ? nth(newValues, kx - ix)
: nth(source, kx - growth)
if a[k] != expectedValue {
reportFailure(
&a,
// FIXME: why do we need to break this string into two parts?
"a[\(kx)] = "
+ "\(a[k]) != expected value \(expectedValue)")
}
}
}
}
}
}
public func expectEqualSequence<
Expected: SequenceType,
Actual: SequenceType
where Expected.Generator.Element == Actual.Generator.Element,
Expected.Generator.Element : Equatable
>(
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
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 !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()
}
}
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<T : Comparable>(
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<T : Comparable> : Comparable {
init(_ first: T, _ second: T) {
self.first = first
self.second = second
}
var first: T
var second: T
}
func == <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return lhs.first == rhs.first && lhs.second == rhs.second
}
func < <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
return lexicographicalCompare(
[ lhs.first, lhs.second ],
[ rhs.first, rhs.second ])
}
public func expectEqualsUnordered<T : Comparable>(
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<ArgumentType, Result : Equatable>(
arguments: [ArgumentType], function1: ArgumentType -> Result,
function2: ArgumentType -> Result
) {
for a in arguments {
let expected = function1(a)
let actual = function2(a)
expectEqual(expected, actual) {
"where the argument is: \(a)"
}
}
}
public func expectEqualMethodsForDomain<
SelfType, ArgumentType, Result : Equatable
>(
selfs: [SelfType], arguments: [ArgumentType],
function1: SelfType -> ArgumentType -> Result,
function2: SelfType -> ArgumentType -> Result
) {
for s in selfs {
for a in arguments {
let expected = function1(s)(a)
let actual = function2(s)(a)
expectEqual(expected, actual) {
"where the first argument is: \(s)\nand the second argument is: \(a)"
}
}
}
}
public func expectEqualUnicodeScalars(
expected: _UnitTestArray<UInt32>, actual: String,
stackTrace: SourceLocStack? = nil,
file: String = __FILE__, line: UWord = __LINE__,
collectMoreInfo: (()->String)? = nil
) {
let actualUnicodeScalars = _UnitTestArray(lazy(actual.unicodeScalars).map { $0.value })
if !equal(expected, 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<T>(
#expectedOneOf: _UnitTestArray<String>, object: T,
file: StaticString = __FILE__, line: UWord = __LINE__
) {
let actual = toString(object)
if !contains(expectedOneOf, actual) {
_anyExpectFailed = true
println("check failed at \(file), line \(line)")
println("expected: any of \(expectedOneOf.debugDescription)")
println("actual: \"\(actual)\"")
println()
}
}
public func expectPrinted<T>(
expected: String, object: T,
file: StaticString = __FILE__, line: UWord = __LINE__
) {
expectPrinted(expectedOneOf: [expected], object, file: file, line: line)
}
public func expectDebugPrinted<T>(
#expectedOneOf: _UnitTestArray<String>, object: T,
file: StaticString = __FILE__, line: UWord = __LINE__
) {
let actual = toDebugString(object)
if !contains(expectedOneOf, actual) {
_anyExpectFailed = true
println("check failed at \(file), line \(line)")
println("expected: any of \(expectedOneOf.debugDescription)")
println("actual: \"\(actual)\"")
println()
}
}
public func expectDebugPrinted<T>(
expected: String, object: T,
file: StaticString = __FILE__, line: UWord = __LINE__
) {
expectDebugPrinted(expectedOneOf: [expected], object, file: file, line: line)
}
func compose<A, B, C>(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<T> {
internal init() {}
internal var returnedNilCounter: Int = 0
}
/// State shared by all generators of a MinimalSequence.
internal class _MinimalGeneratorSharedState<T> {
internal init(_ data: [T]) {
self.data = data
}
internal let data: [T]
internal var i: 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<T> : GeneratorType {
public init<S : SequenceType where S.Generator.Element == T>(_ s: S) {
self._sharedState = _MinimalGeneratorSharedState(Array(s))
}
public init(_ data: [T]) {
self._sharedState = _MinimalGeneratorSharedState(data)
}
internal init(_ _sharedState: _MinimalGeneratorSharedState<T>) {
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<T> =
_MinimalGeneratorPrivateState()
internal let _sharedState: _MinimalGeneratorSharedState<T>
}
//===----------------------------------------------------------------------===//
// MinimalSequence
//===----------------------------------------------------------------------===//
public enum UnderestimateCountBehavior {
/// Return the actual number of elements.
case Precise
/// 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<T> : SequenceType {
public init<S : SequenceType where S.Generator.Element == T>(
_ s: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
let data = Array(s)
self._sharedState = _MinimalGeneratorSharedState(data)
switch underestimatedCount {
case .Precise:
self.underestimatedCount = data.count
case .Overestimate:
self.underestimatedCount = data.count * 3 + 5
case .Value(let count):
self.underestimatedCount = count
}
}
public func generate() -> MinimalGenerator<T> {
return MinimalGenerator(_sharedState)
}
public var underestimatedCount: Int
internal let _sharedState: _MinimalGeneratorSharedState<T>
}
public func ~> <T> (
s: MinimalSequence<T>, _: (_UnderestimateCount, ())
) -> Int {
return s.underestimatedCount
}
//===----------------------------------------------------------------------===//
// MinimalForwardIndex
//===----------------------------------------------------------------------===//
public struct MinimalForwardIndex : ForwardIndexType {
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() -> MinimalForwardIndex {
expectNotEqual(_endIndex, _position)
return MinimalForwardIndex(position: _position + 1, endIndex: _endIndex)
}
internal var _position: Int
internal var _endIndex: Int
}
public func == (lhs: MinimalForwardIndex, rhs: MinimalForwardIndex) -> Bool {
return lhs._position == rhs._position
}
//===----------------------------------------------------------------------===//
// 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)
}
internal var _position: Int
internal var _startIndex: Int
internal var _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)
}
internal var _position: Int
internal var _startIndex: Int
internal var _endIndex: Int
}
public func == (
lhs: MinimalRandomAccessIndex,
rhs: MinimalRandomAccessIndex
) -> Bool {
return lhs._position == rhs._position
}
//===----------------------------------------------------------------------===//
// Minimal***Collection
//===----------------------------------------------------------------------===//
%for traversal in [ 'Forward', 'Bidirectional', 'RandomAccess' ]:
% Self = 'Minimal%sCollection' % traversal
% Index = 'Minimal%sIndex' % traversal
/// A minimal implementation of CollectionType with extra checks.
public struct ${Self}<T> : CollectionType {
public init<S : SequenceType where S.Generator.Element == T>(
_ s: S,
underestimatedCount: UnderestimateCountBehavior = .Value(0)
) {
self._data = Array(s)
switch underestimatedCount {
case .Precise:
self.underestimatedCount = _data.count
case .Overestimate:
self.underestimatedCount = _data.count * 3 + 5
case .Value(let count):
self.underestimatedCount = count
}
}
public func generate() -> MinimalGenerator<T> {
return MinimalGenerator(_data)
}
public var startIndex: ${Index} {
return ${Index}(position: 0, startIndex: 0, endIndex: _data.endIndex)
}
public var endIndex: ${Index} {
return ${Index}(
position: _data.endIndex, startIndex: 0, endIndex: _data.endIndex)
}
public subscript(i: ${Index}) -> T {
return _data[i._position]
}
public var underestimatedCount: Int
internal let _data: [T]
}
public func ~> <T> (
c: ${Self}<T>, _: (_UnderestimateCount, ())
) -> Int {
return c.underestimatedCount
}
%end
// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End: