mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Mechanically add "Type" to the end of any protocol names that don't end in "Type," "ible," or "able." Also, drop "Type" from the end of any associated type names, except for those of the *LiteralConvertible protocols. There are obvious improvements to make in some of these names, which can be handled with separate commits. Fixes <rdar://problem/17165920> Protocols `Integer` etc should get uglier names. Swift SVN r19883
474 lines
12 KiB
Swift
474 lines
12 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 += 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 ? " ; \(loc.comment!)" : ""
|
|
println(" #\(i): \(loc.file):\(loc.line)\(comment)")
|
|
}
|
|
}
|
|
}
|
|
|
|
var _anyExpectFailed = false
|
|
|
|
public func expectEqual<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("expected: \"\(expected)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println("actual: \"\(actual)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println()
|
|
}
|
|
}
|
|
|
|
public func expectEqual<T : Equatable>(
|
|
expected: T, actual: T,
|
|
stackTrace: SourceLocStack? = nil,
|
|
collectMoreInfo: () -> String,
|
|
file: String = __FILE__, line: UWord = __LINE__
|
|
) {
|
|
if expected != actual {
|
|
_anyExpectFailed = true
|
|
println("check failed at \(file), line \(line)")
|
|
_printStackTrace(stackTrace)
|
|
println("expected: \"\(expected)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println("actual: \"\(actual)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println(collectMoreInfo())
|
|
println()
|
|
}
|
|
}
|
|
|
|
public func expectNotEqual<T : Equatable>(
|
|
expected: T, actual: T,
|
|
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_getTypeName(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 || expected != actual! {
|
|
_anyExpectFailed = true
|
|
println("check failed at \(file), line \(line)")
|
|
println("expected: \"\(expected)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println("actual: \"\(actual)\" (of type \(_stdlib_getTypeName(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,
|
|
file: String = __FILE__, line: UWord = __LINE__
|
|
) {
|
|
if expected != actual {
|
|
_anyExpectFailed = true
|
|
println("check failed at \(file), line \(line)")
|
|
_printStackTrace(stackTrace)
|
|
println("expected: \"\(expected)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println("actual: \"\(actual)\" (of type \(_stdlib_getTypeName(actual)))")
|
|
println()
|
|
}
|
|
}
|
|
|
|
public func expectEqual${Generic}(
|
|
expected: ${EquatableType}, actual: ${EquatableType},
|
|
stackTrace: SourceLocStack? = nil,
|
|
collectMoreInfo: () -> String,
|
|
file: String = __FILE__, line: UWord = __LINE__
|
|
) {
|
|
if expected != actual {
|
|
_anyExpectFailed = true
|
|
println("check failed at \(file), line \(line)")
|
|
_printStackTrace(stackTrace)
|
|
println("expected: \"\(expected)\" (of type \(_stdlib_getTypeName(expected)))")
|
|
println("actual: \"\(actual)\" (of type \(_stdlib_getTypeName(actual)))")
|
|
println(collectMoreInfo())
|
|
println()
|
|
}
|
|
}
|
|
|
|
|
|
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_getTypeName(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, LogicValueType {
|
|
init(isPass: Bool) {
|
|
self._isPass = isPass
|
|
}
|
|
|
|
public func getLogicValue() -> 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},
|
|
file: String = __FILE__, line: UWord = __LINE__
|
|
) {
|
|
if actual {
|
|
_anyExpectFailed = true
|
|
println("check failed at \(file), line \(line)")
|
|
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 {
|
|
_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 {
|
|
_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 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 += 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 += 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
|
|
}
|
|
}
|
|
}
|
|
|
|
// ${'Local Variables'}:
|
|
// eval: (read-only-mode 1)
|
|
// End:
|