Files
swift-mirror/stdlib/unittest/StdlibUnittest.swift.gyb
Joe Pamer 94dac129d4 Remove the BooleanType conformance from optional types (rdar://problem/17110911)
To limit user confusion when using conditional expressions of type Bool?, we've decided to remove the BooleanType (aka "LogicValue") conformance from optional types. (If users would like to use an expression of type Bool? as a conditional, they'll need to check against nil.)

Note: This change effectively regresses the "case is" pattern over types, since it currently demands a BooleanType conformance. I've filed rdar://problem/17791533 to track reinstating it if necessary.

Swift SVN r20637
2014-07-28 19:20:39 +00:00

515 lines
14 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 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
}
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))
}
}
internal 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)")
}
}
}
var _anyExpectFailed = false
public func expectEqual<T : Equatable>(
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<T>(
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<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()
}
}
// Array<T> is not Equatable if T is. Provide additional overloads.
// Same for Dictionary.
%for (Generic, EquatableType) in [
% ('<T : Equatable>', 'ContiguousArray<T>'),
% ('<T : Equatable>', 'Slice<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,
_ collectMoreInfo: (()->String)? = nil,
file: String = __FILE__, line: UWord = __LINE__
) {
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, 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,
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)")
println()
}
}
public func expectFalse(
actual: ${BoolType},
stackTrace: SourceLocStack? = 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)")
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 struct TestCase {
public init(_ name: String) {
self.name = name
}
public mutating func test(name: String, testFunction: () -> ()) {
_tests.append(_Test(name: name, code: testFunction))
}
public mutating func run() {
var anyTestFailed = false
for t in _tests {
var fullTestName = "\(name).\(t.name)"
println("[ RUN ] \(fullTestName)")
_anyExpectFailed = false
t.code()
if _anyExpectFailed {
anyTestFailed = true
println("[ FAIL ] \(fullTestName)")
} else {
println("[ OK ] \(fullTestName)")
}
}
if anyTestFailed {
println("Some tests failed, aborting")
abort()
} else {
println("\(name): All tests passed")
}
}
struct _Test {
var name: String
var code: () -> ()
}
var name: String
var _tests: [_Test] = []
}
// These APIs don't really belong in a unittesting library, but are useful
// in tests, and stdlib does not have such facilities yet.
public func asHex(a: [UInt8]) -> String {
return "[ " + ", ".join(a.map { "0x" + String($0, radix: 16) }) + " ]"
}
public func asHex(a: [UInt32]) -> String {
return "[ " + ", ".join(a.map { "0x" + String($0, radix: 16) }) + " ]"
}
//
// Helpers that verify invariants of various stdlib types.
//
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)
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 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..<endNumericIndex])
let slice = sliceable[start..<end]
checkCollection(expectedSlice, slice, stackTrace.withCurrentLoc())
if end != sliceable.endIndex {
++end
}
}
if start != sliceable.endIndex {
++start
}
}
}
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,
_ 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: