1
1
import Foundation
2
2
3
3
// swiftlint:disable:next identifier_name
4
- public let DefaultDelta = 0.0001
5
-
6
- internal func isCloseTo( _ actualValue: NMBDoubleConvertible ? ,
7
- expectedValue: NMBDoubleConvertible ,
8
- delta: Double )
9
- -> PredicateResult {
10
- let errorMessage = " be close to < \( stringify ( expectedValue) ) > (within \( stringify ( delta) ) ) "
11
- return PredicateResult (
12
- bool: actualValue != nil &&
13
- abs ( actualValue!. doubleValue - expectedValue. doubleValue) < delta,
14
- message: . expectedCustomValueTo( errorMessage, actual: " < \( stringify ( actualValue) ) > " )
15
- )
4
+ public let DefaultDelta : Double = 0.0001
5
+
6
+ public func defaultDelta< F: FloatingPoint > ( ) -> F { 1 / 10000 /* 0.0001 */ }
7
+
8
+ internal func isCloseTo< Value: FloatingPoint > (
9
+ _ actualValue: Value ? ,
10
+ expectedValue: Value ,
11
+ delta: Value
12
+ ) -> PredicateResult {
13
+ let errorMessage = " be close to < \( stringify ( expectedValue) ) > (within \( stringify ( delta) ) ) "
14
+ return PredicateResult (
15
+ bool: actualValue != nil &&
16
+ abs ( actualValue! - expectedValue) < delta,
17
+ message: . expectedCustomValueTo( errorMessage, actual: " < \( stringify ( actualValue) ) > " )
18
+ )
19
+ }
20
+
21
+ internal func isCloseTo(
22
+ _ actualValue: NMBDoubleConvertible ? ,
23
+ expectedValue: NMBDoubleConvertible ,
24
+ delta: Double
25
+ ) -> PredicateResult {
26
+ let errorMessage = " be close to < \( stringify ( expectedValue) ) > (within \( stringify ( delta) ) ) "
27
+ return PredicateResult (
28
+ bool: actualValue != nil &&
29
+ abs ( actualValue!. doubleValue - expectedValue. doubleValue) < delta,
30
+ message: . expectedCustomValueTo( errorMessage, actual: " < \( stringify ( actualValue) ) > " )
31
+ )
16
32
}
17
33
18
34
/// A Nimble matcher that succeeds when a value is close to another. This is used for floating
19
35
/// point values which can have imprecise results when doing arithmetic on them.
20
36
///
21
37
/// @see equal
22
- public func beCloseTo< Value: NMBDoubleConvertible > ( _ expectedValue: Value , within delta: Double = DefaultDelta) -> Predicate < Value > {
38
+ public func beCloseTo< Value: FloatingPoint > (
39
+ _ expectedValue: Value ,
40
+ within delta: Value = defaultDelta ( )
41
+ ) -> Predicate < Value > {
23
42
return Predicate . define { actualExpression in
24
43
return isCloseTo ( try actualExpression. evaluate ( ) , expectedValue: expectedValue, delta: delta)
25
44
}
26
45
}
27
46
28
- private func beCloseTo( _ expectedValue: NMBDoubleConvertible , within delta: Double = DefaultDelta) -> Predicate < NMBDoubleConvertible > {
47
+ /// A Nimble matcher that succeeds when a value is close to another. This is used for floating
48
+ /// point values which can have imprecise results when doing arithmetic on them.
49
+ ///
50
+ /// @see equal
51
+ public func beCloseTo< Value: NMBDoubleConvertible > (
52
+ _ expectedValue: Value ,
53
+ within delta: Double = DefaultDelta
54
+ ) -> Predicate < Value > {
55
+ return Predicate . define { actualExpression in
56
+ return isCloseTo ( try actualExpression. evaluate ( ) , expectedValue: expectedValue, delta: delta)
57
+ }
58
+ }
59
+
60
+ private func beCloseTo(
61
+ _ expectedValue: NMBDoubleConvertible ,
62
+ within delta: Double = DefaultDelta
63
+ ) -> Predicate < NMBDoubleConvertible > {
29
64
return Predicate . define { actualExpression in
30
65
return isCloseTo ( try actualExpression. evaluate ( ) , expectedValue: expectedValue, delta: delta)
31
66
}
@@ -61,48 +96,68 @@ extension NMBPredicate {
61
96
}
62
97
#endif
63
98
64
- public func beCloseTo( _ expectedValues: [ Double ] , within delta: Double = DefaultDelta) -> Predicate < [ Double ] > {
99
+ public func beCloseTo< Value: FloatingPoint , Values: Collection > (
100
+ _ expectedValues: Values ,
101
+ within delta: Value = defaultDelta ( )
102
+ ) -> Predicate < Values > where Values. Element == Value {
65
103
let errorMessage = " be close to < \( stringify ( expectedValues) ) > (each within \( stringify ( delta) ) ) "
66
104
return Predicate . simple ( errorMessage) { actualExpression in
67
- if let actual = try actualExpression. evaluate ( ) {
68
- if actual. count != expectedValues. count {
105
+ guard let actualValues = try actualExpression. evaluate ( ) else {
106
+ return . doesNotMatch
107
+ }
108
+
109
+ if actualValues. count != expectedValues. count {
110
+ return . doesNotMatch
111
+ }
112
+
113
+ for index in actualValues. indices {
114
+ if abs ( actualValues [ index] - expectedValues[ index] ) > delta {
69
115
return . doesNotMatch
70
- } else {
71
- for (index, actualItem) in actual. enumerated ( ) {
72
- if fabs ( actualItem - expectedValues[ index] ) > delta {
73
- return . doesNotMatch
74
- }
75
- }
76
- return . matches
77
116
}
78
117
}
79
- return . doesNotMatch
118
+ return . matches
80
119
}
81
120
}
82
121
83
122
// MARK: - Operators
84
123
85
124
infix operator ≈ : ComparisonPrecedence
86
125
87
- extension Expectation where T == [ Double ] {
126
+ extension Expectation where T: Collection , T . Element : FloatingPoint {
88
127
// swiftlint:disable:next identifier_name
89
- public static func ≈ ( lhs: Expectation , rhs: [ Double ] ) {
128
+ public static func ≈ ( lhs: Expectation , rhs: T ) {
90
129
lhs. to ( beCloseTo ( rhs) )
91
130
}
92
131
}
93
132
94
- extension Expectation where T == NMBDoubleConvertible {
133
+ extension Expectation where T: FloatingPoint {
95
134
// swiftlint:disable:next identifier_name
96
- public static func ≈ ( lhs: Expectation , rhs: NMBDoubleConvertible ) {
135
+ public static func ≈ ( lhs: Expectation , rhs: T ) {
97
136
lhs. to ( beCloseTo ( rhs) )
98
137
}
99
138
100
139
// swiftlint:disable:next identifier_name
101
- public static func ≈ ( lhs: Expectation , rhs: ( expected: NMBDoubleConvertible , delta: Double ) ) {
140
+ public static func ≈ ( lhs: Expectation , rhs: ( expected: T , delta: T ) ) {
102
141
lhs. to ( beCloseTo ( rhs. expected, within: rhs. delta) )
103
142
}
104
143
105
- public static func == ( lhs: Expectation , rhs: ( expected: NMBDoubleConvertible , delta: Double ) ) {
144
+ public static func == ( lhs: Expectation , rhs: ( expected: T , delta: T ) ) {
145
+ lhs. to ( beCloseTo ( rhs. expected, within: rhs. delta) )
146
+ }
147
+ }
148
+
149
+ extension Expectation where T: NMBDoubleConvertible {
150
+ // swiftlint:disable:next identifier_name
151
+ public static func ≈ ( lhs: Expectation , rhs: T ) {
152
+ lhs. to ( beCloseTo ( rhs) )
153
+ }
154
+
155
+ // swiftlint:disable:next identifier_name
156
+ public static func ≈ ( lhs: Expectation , rhs: ( expected: T , delta: Double ) ) {
157
+ lhs. to ( beCloseTo ( rhs. expected, within: rhs. delta) )
158
+ }
159
+
160
+ public static func == ( lhs: Expectation , rhs: ( expected: T , delta: Double ) ) {
106
161
lhs. to ( beCloseTo ( rhs. expected, within: rhs. delta) )
107
162
}
108
163
}
@@ -115,6 +170,10 @@ precedencegroup PlusMinusOperatorPrecedence {
115
170
116
171
infix operator ± : PlusMinusOperatorPrecedence
117
172
// swiftlint:disable:next identifier_name
118
- public func ± ( lhs: NMBDoubleConvertible , rhs: Double ) -> ( expected: NMBDoubleConvertible , delta: Double ) {
173
+ public func ± < Value: FloatingPoint > ( lhs: Value , rhs: Value ) -> ( expected: Value , delta: Value ) {
174
+ return ( expected: lhs, delta: rhs)
175
+ }
176
+ // swiftlint:disable:next identifier_name
177
+ public func ± < Value: NMBDoubleConvertible > ( lhs: Value , rhs: Double ) -> ( expected: Value , delta: Double ) {
119
178
return ( expected: lhs, delta: rhs)
120
179
}
0 commit comments