-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathHamcrest.swift
122 lines (105 loc) · 4.47 KB
/
Hamcrest.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import Foundation
import Swift
import XCTest
/// Reporter function that is called whenever a Hamcrest assertion fails.
/// By default this calls XCTFail, except in Playgrounds where it does nothing.
/// This is intended for testing Hamcrest itself.
nonisolated(unsafe) public var HamcrestReportFunction: (_: String, _ file: StaticString, _ line: UInt) -> () = HamcrestDefaultReportFunction
nonisolated(unsafe) public let HamcrestDefaultReportFunction =
isPlayground()
? {message, file, line in}
: {message, file, line in XCTFail(message, file: file, line: line)}
// MARK: helpers
func filterNotNil<T>(_ array: [T?]) -> [T] {
return array.filter({$0 != nil}).map({$0!})
}
func delegateMatching<T>(_ value: T, _ matcher: Matcher<T>, _ mismatchDescriber: (String?) -> String?) -> MatchResult {
switch matcher.matches(value) {
case .match:
return .match
case let .mismatch(mismatchDescription):
return .mismatch(mismatchDescriber(mismatchDescription))
}
}
func equalToWithoutDescription<T: Equatable>(_ expectedValue: T) -> Matcher<T> {
return describedAs(describe(expectedValue), equalTo(expectedValue))
}
func isPlayground() -> Bool {
let infoDictionary = Bundle.main.infoDictionary
let bundleIdentifier = infoDictionary?["CFBundleIdentifier"]
return (bundleIdentifier as? String)?.hasPrefix("com.apple.dt.Xcode") ?? false
}
// MARK: assertThrows
@discardableResult public func assertThrows<T>(_ value: @autoclosure () throws -> T, file: StaticString = #file, line: UInt = #line) -> String {
do {
_ = try value()
return reportResult(describeExpectedError(), file: file, line: line)
} catch {
return reportResult(nil, file: file, line: line)
}
}
@discardableResult public func assertThrows<S, T: Error>(_ value: @autoclosure () throws -> S, _ error: T, file: String = #file, line: UInt = #line) -> String where T: Equatable {
return assertThrows(try value(), equalToWithoutDescription(error), file: file, line: line)
}
@discardableResult public func assertThrows<S, T: Error>(_ value: @autoclosure () throws -> S, _ matcher: Matcher<T>, file: String = #file, line: UInt = #line) -> String {
return reportResult(applyErrorMatcher(matcher, toBlock: value))
}
@discardableResult private func applyErrorMatcher<S, T: Error>(_ matcher: Matcher<T>, toBlock: () throws -> S) -> String? {
do {
_ = try toBlock()
return describeExpectedError(matcher.description)
} catch let error as T {
let match = matcher.matches(error)
switch match {
case .match:
return nil
case let .mismatch(mismatchDescription):
return describeErrorMismatch(error, matcher.description, mismatchDescription)
}
} catch let error {
return describeErrorMismatch(error, matcher.description, nil)
}
}
// MARK: assertNotThrows
@discardableResult public func assertNotThrows<T>(_ value: @autoclosure () throws -> T, file: StaticString = #file, line: UInt = #line) -> String {
do {
_ = try value()
return reportResult(nil, file: file, line: line)
} catch {
return reportResult(describeUnexpectedError(), file: file, line: line)
}
}
// MARK: assertThat
@discardableResult public func assertThat<T>(_ value: @autoclosure () throws -> T, _ matcher: Matcher<T>, message: String? = nil, file: StaticString = #file, line: UInt = #line) -> String {
return reportResult(applyMatcher(matcher, toValue: value), message: message, file: file, line: line)
}
@discardableResult public func applyMatcher<T>(_ matcher: Matcher<T>, toValue: () throws -> T) -> String? {
do {
let value = try toValue()
let match = matcher.matches(value)
switch match {
case .match:
return nil
case let .mismatch(mismatchDescription):
return describeMismatch(value, matcher.description, mismatchDescription)
}
} catch let error {
return describeError(error)
}
}
func reportResult(_ possibleResult: String?, message: String? = nil, file: StaticString = #file, line: UInt = #line)
-> String {
if let possibleResult = possibleResult {
let result: String
if let message = message {
result = "\(message) - \(possibleResult)"
} else {
result = possibleResult
}
HamcrestReportFunction(result, file, line)
return result
} else {
// The return value is just intended for Playgrounds.
return "✓"
}
}