//===--- 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..( 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( 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( 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: // Array->NSArray implicit conversion insanity public func expectOptionalEqual( 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 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, 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, BooleanType { 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( value: Optional, 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( value: Optional, 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..