|
| 1 | +/// An expectation that can be matched with a value. |
| 2 | +public struct Expectation<Value>: Printable { |
| 3 | + public private(set) var description: String |
| 4 | + |
| 5 | + private let matchesFunc: Value -> Bool |
| 6 | + |
| 7 | + /// Initializes a new expectation with the given description and matching |
| 8 | + /// function. |
| 9 | + public init(description: String = "<func>", matches matchesFunc: Value -> Bool) { |
| 10 | + self.description = description |
| 11 | + self.matchesFunc = matchesFunc |
| 12 | + } |
| 13 | + |
| 14 | + /// Checks whether this expectation matches the given value. |
| 15 | + public func matches(value: Value) -> Bool { |
| 16 | + return matchesFunc(value) |
| 17 | + } |
| 18 | +} |
| 19 | + |
| 20 | +/// Returns a new expectation with the given matching function. |
| 21 | +/// |
| 22 | +/// - SeeAlso: `Expectation.init<Value>(description: String, matches: Value -> Bool)` |
| 23 | +public func matches<Value>(matches: Value -> Bool) -> Expectation<Value> { |
| 24 | + return Expectation(matches: matches) |
| 25 | +} |
| 26 | + |
| 27 | +/// Returns a new expectation that matches anything. |
| 28 | +/// |
| 29 | +/// - SeeAlso: `Expectation.init<Value>()` |
| 30 | +public func any<Value>() -> Expectation<Value> { |
| 31 | + return Expectation(description: "_", matches: { _ in true }) |
| 32 | +} |
| 33 | + |
| 34 | +/// Returns a new expectation that matches the given value. |
| 35 | +/// |
| 36 | +/// - SeeAlso: `Expectation.init<Value>(value: Value)` |
| 37 | +public func equals<Value: Equatable>(value: Value) -> Expectation<Value> { |
| 38 | + return Expectation(description: "\(value)", matches: { actualValue in value == actualValue }) |
| 39 | +} |
| 40 | + |
| 41 | +/// Returns a new expectation that matches the given 2-tuple. |
| 42 | +public func equals<A: Equatable, B: Equatable>(values: (A, B)) -> Expectation<(A, B)> { |
| 43 | + return Expectation(description: "\(values)") { actualValues in |
| 44 | + return values.0 == actualValues.0 |
| 45 | + && values.1 == actualValues.1 |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +/// Returns a new expectation that matches the given 3-tuple. |
| 50 | +public func equals<A: Equatable, B: Equatable, C: Equatable>(values: (A, B, C)) -> Expectation<(A, B, C)> { |
| 51 | + return Expectation(description: "\(values)") { actualValues in |
| 52 | + return values.0 == actualValues.0 |
| 53 | + && values.1 == actualValues.1 |
| 54 | + && values.2 == actualValues.2 |
| 55 | + } |
| 56 | +} |
| 57 | + |
| 58 | +/// Returns a new expectation that matches the given 4-tuple. |
| 59 | +public func equals<A: Equatable, B: Equatable, C: Equatable, D: Equatable>(values: (A, B, C, D)) -> Expectation<(A, B, C, D)> { |
| 60 | + return Expectation(description: "\(values)") { actualValues in |
| 61 | + return values.0 == actualValues.0 |
| 62 | + && values.1 == actualValues.1 |
| 63 | + && values.2 == actualValues.2 |
| 64 | + && values.3 == actualValues.3 |
| 65 | + } |
| 66 | +} |
| 67 | + |
| 68 | +/// Returns a new expectation that matches the given 5-tuple. |
| 69 | +public func equals<A: Equatable, B: Equatable, C: Equatable, D: Equatable, E: Equatable>(values: (A, B, C, D, E)) -> Expectation<(A, B, C, D, E)> { |
| 70 | + return Expectation(description: "\(values)") { actualValues in |
| 71 | + // Expression was too complex to be solved in reasonable time; [...] |
| 72 | + let equals = values.0 == actualValues.0 |
| 73 | + && values.1 == actualValues.1 |
| 74 | + && values.2 == actualValues.2 |
| 75 | + && values.3 == actualValues.3 |
| 76 | + && values.4 == actualValues.4 |
| 77 | + return equals |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +/// Returns a new expectation that matches the given array. |
| 82 | +public func equals<Element: Equatable>(value: [Element]) -> Expectation<[Element]> { |
| 83 | + return Expectation(description: "\(value)") { actualValue in value == actualValue } |
| 84 | +} |
| 85 | + |
| 86 | +/// Returns a new expectation that matches the given dictionary. |
| 87 | +public func equals<Key: Equatable, Value: Equatable>(value: [Key: Value]) -> Expectation<[Key: Value]> { |
| 88 | + return Expectation(description: "\(value)") { actualValue in value == actualValue } |
| 89 | +} |
| 90 | + |
| 91 | +/// Conforming types can be converted to an expectation. |
| 92 | +public protocol ExpectationConvertible { |
| 93 | + /// The type of value with which this type, when converted to an |
| 94 | + /// expectation, can be matched. |
| 95 | + typealias ValueType |
| 96 | + |
| 97 | + /// Converts this type to an expectation. |
| 98 | + func expectation() -> Expectation<ValueType> |
| 99 | +} |
| 100 | + |
| 101 | +extension Expectation: ExpectationConvertible { |
| 102 | + public func expectation() -> Expectation<Value> { |
| 103 | + return self |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +/// Returns a new expectation that matches the given 2-tuple of expectations. |
| 108 | +public func matches<A: ExpectationConvertible, B: ExpectationConvertible>(values: (A, B)) -> Expectation<(A.ValueType, B.ValueType)> { |
| 109 | + return Expectation(description: "\(values)") { actualValues in |
| 110 | + return values.0.expectation().matches(actualValues.0) |
| 111 | + && values.1.expectation().matches(actualValues.1) |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +/// Returns a new expectation that matches the given 3-tuple of expectations. |
| 116 | +public func matches<A: ExpectationConvertible, B: ExpectationConvertible, C: ExpectationConvertible>(values: (A, B, C)) -> Expectation<(A.ValueType, B.ValueType, C.ValueType)> { |
| 117 | + return Expectation(description: "\(values)") { actualValues in |
| 118 | + return values.0.expectation().matches(actualValues.0) |
| 119 | + && values.1.expectation().matches(actualValues.1) |
| 120 | + && values.2.expectation().matches(actualValues.2) |
| 121 | + } |
| 122 | +} |
| 123 | + |
| 124 | +/// Returns a new expectation that matches the given 4-tuple of expectations. |
| 125 | +public func matches<A: ExpectationConvertible, B: ExpectationConvertible, C: ExpectationConvertible, D: ExpectationConvertible>(values: (A, B, C, D)) -> Expectation<(A.ValueType, B.ValueType, C.ValueType, D.ValueType)> { |
| 126 | + return Expectation(description: "\(values)") { actualValues in |
| 127 | + return values.0.expectation().matches(actualValues.0) |
| 128 | + && values.1.expectation().matches(actualValues.1) |
| 129 | + && values.2.expectation().matches(actualValues.2) |
| 130 | + && values.3.expectation().matches(actualValues.3) |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +/// Returns a new expectation that matches the given 5-tuple of expectations. |
| 135 | +public func matches<A: ExpectationConvertible, B: ExpectationConvertible, C: ExpectationConvertible, D: ExpectationConvertible, E: ExpectationConvertible>(values: (A, B, C, D, E)) -> Expectation<(A.ValueType, B.ValueType, C.ValueType, D.ValueType, E.ValueType)> { |
| 136 | + return Expectation(description: "\(values)") { actualValues in |
| 137 | + return values.0.expectation().matches(actualValues.0) |
| 138 | + && values.1.expectation().matches(actualValues.1) |
| 139 | + && values.2.expectation().matches(actualValues.2) |
| 140 | + && values.3.expectation().matches(actualValues.3) |
| 141 | + && values.4.expectation().matches(actualValues.4) |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +/// Returns a new expectation that matches the given array of expectations. |
| 146 | +public func matches<Element: ExpectationConvertible>(values: [Element]) -> Expectation<[Element.ValueType]> { |
| 147 | + return Expectation(description: "\(values)") { actualValues in |
| 148 | + if values.count != actualValues.count { |
| 149 | + return false |
| 150 | + } |
| 151 | + |
| 152 | + for (element, actualElement) in zip(values, actualValues) { |
| 153 | + if !element.expectation().matches(actualElement) { |
| 154 | + return false |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + return true |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +/// Returns a new expectation that matches the given dictionary of expectations. |
| 163 | +public func matches<Key: Hashable, Value: ExpectationConvertible>(values: [Key: Value]) -> Expectation<[Key: Value.ValueType]> { |
| 164 | + return Expectation(description: "\(values)") { actualValues in |
| 165 | + if values.count != actualValues.count { |
| 166 | + return false |
| 167 | + } |
| 168 | + |
| 169 | + for (key, value) in values { |
| 170 | + if !(actualValues[key].map { actualValue in value.expectation().matches(actualValue) } ?? false) { |
| 171 | + return false |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + return true |
| 176 | + } |
| 177 | +} |
0 commit comments