@@ -20,6 +20,7 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
20
20
" expect(10) <= 10 \n " ,
21
21
" expect(x) === x " ,
22
22
" expect(10) == 10 " ,
23
+ " expect(success) == true " ,
23
24
" expect(object.asyncFunction()).toEventually(equal(1)) \n " ,
24
25
" expect(actual).to(haveCount(expected)) \n " ,
25
26
"""
@@ -39,6 +40,8 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
39
40
" ↓expect(10).to(beLessThan(11)) \n " ,
40
41
" ↓expect(10).to(beLessThanOrEqualTo(10)) \n " ,
41
42
" ↓expect(x).to(beIdenticalTo(x)) \n " ,
43
+ " ↓expect(success).to(beTrue()) \n " ,
44
+ " ↓expect(success).to(beFalse()) \n " ,
42
45
" expect(10) > 2 \n ↓expect(10).to(beGreaterThan(2)) \n "
43
46
] ,
44
47
corrections: [
@@ -53,20 +56,39 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
53
56
" ↓expect(10).to(beLessThan(11)) \n " : " expect(10) < 11 \n " ,
54
57
" ↓expect(10).to(beLessThanOrEqualTo(10)) \n " : " expect(10) <= 10 \n " ,
55
58
" ↓expect(x).to(beIdenticalTo(x)) \n " : " expect(x) === x \n " ,
59
+ " ↓expect(success).to(beTrue()) \n " : " expect(success) == true \n " ,
60
+ " ↓expect(success).to(beFalse()) \n " : " expect(success) == false \n " ,
61
+ " ↓expect(success).toNot(beFalse()) \n " : " expect(success) != false \n " ,
62
+ " ↓expect(success).toNot(beTrue()) \n " : " expect(success) != true \n " ,
56
63
" expect(10) > 2 \n ↓expect(10).to(beGreaterThan(2)) \n " : " expect(10) > 2 \n expect(10) > 2 \n "
57
64
]
58
65
)
59
66
60
- fileprivate typealias Operators = ( to: String ? , toNot: String ? )
61
67
fileprivate typealias MatcherFunction = String
62
68
63
- private let operatorsMapping : [ MatcherFunction : Operators ] = [
64
- " equal " : ( to: " == " , toNot: " != " ) ,
65
- " beIdenticalTo " : ( to: " === " , toNot: " !== " ) ,
66
- " beGreaterThan " : ( to: " > " , toNot: nil ) ,
67
- " beGreaterThanOrEqualTo " : ( to: " >= " , toNot: nil ) ,
68
- " beLessThan " : ( to: " < " , toNot: nil ) ,
69
- " beLessThanOrEqualTo " : ( to: " <= " , toNot: nil )
69
+ fileprivate enum Arity {
70
+ case nullary( analogueValue: String )
71
+ case withArguments
72
+
73
+ var hasArguments : Bool {
74
+ guard case . withArguments = self else {
75
+ return false
76
+ }
77
+ return true
78
+ }
79
+ }
80
+
81
+ fileprivate typealias PredicateDescription = ( to: String ? , toNot: String ? , arity: Arity )
82
+
83
+ private let predicatesMapping : [ MatcherFunction : PredicateDescription ] = [
84
+ " equal " : ( to: " == " , toNot: " != " , . withArguments) ,
85
+ " beIdenticalTo " : ( to: " === " , toNot: " !== " , . withArguments) ,
86
+ " beGreaterThan " : ( to: " > " , toNot: nil , . withArguments) ,
87
+ " beGreaterThanOrEqualTo " : ( to: " >= " , toNot: nil , . withArguments) ,
88
+ " beLessThan " : ( to: " < " , toNot: nil , . withArguments) ,
89
+ " beLessThanOrEqualTo " : ( to: " <= " , toNot: nil , . withArguments) ,
90
+ " beTrue " : ( to: " == " , toNot: " != " , . nullary( analogueValue: " true " ) ) ,
91
+ " beFalse " : ( to: " == " , toNot: " != " , . nullary( analogueValue: " false " ) )
70
92
]
71
93
72
94
public func validate( file: File ) -> [ StyleViolation ] {
@@ -79,11 +101,17 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
79
101
}
80
102
81
103
private func violationMatchesRanges( in file: File ) -> [ NSRange ] {
82
- let operatorNames = operatorsMapping. keys
83
- let operatorsPattern = " ( " + operatorNames. joined ( separator: " | " ) + " ) "
104
+ let operandPattern = " (.(?!expect \\ ())+? "
105
+
106
+ let operatorsPattern = " ( " + predicatesMapping. map { name, predicateDescription in
107
+ let argumentsPattern = predicateDescription. arity. hasArguments
108
+ ? operandPattern
109
+ : " "
110
+
111
+ return " \( name) \\ ( \( argumentsPattern) \\ ) "
112
+ } . joined ( separator: " | " ) + " ) "
84
113
85
- let variablePattern = " (.(?!expect \\ ())+? "
86
- let pattern = " expect \\ ( \( variablePattern) \\ ) \\ .to(Not)? \\ ( \( operatorsPattern) \\ ( \( variablePattern) \\ ) \\ ) "
114
+ let pattern = " expect \\ ( \( operandPattern) \\ ) \\ .to(Not)? \\ ( \( operatorsPattern) \\ ) "
87
115
88
116
let excludingKinds = SyntaxKind . commentKinds
89
117
@@ -117,7 +145,7 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
117
145
var contents = file. contents
118
146
119
147
for range in matches. sorted ( by: { $0. location > $1. location } ) {
120
- for (functionName, operatorCorrections) in operatorsMapping {
148
+ for (functionName, operatorCorrections) in predicatesMapping {
121
149
guard let correctedString = contents. replace ( function: functionName,
122
150
with: operatorCorrections,
123
151
in: range)
@@ -141,26 +169,35 @@ public struct NimbleOperatorRule: ConfigurationProviderRule, OptInRule, Correcta
141
169
private extension String {
142
170
/// Returns corrected string if the correction is possible, otherwise returns nil.
143
171
func replace( function name: NimbleOperatorRule . MatcherFunction ,
144
- with operators : NimbleOperatorRule . Operators ,
172
+ with predicateDescription : NimbleOperatorRule . PredicateDescription ,
145
173
in range: NSRange ) -> String ? {
146
174
let anything = " \\ s*(.*?) \\ s* "
147
175
148
- let toPattern = ( " expect \\ ( \( anything) \\ ) \\ .to \\ ( \( name) \\ ( \( anything) \\ ) \\ ) " , operators. to)
149
- let toNotPattern = ( " expect \\ ( \( anything) \\ ) \\ .toNot \\ ( \( name) \\ ( \( anything) \\ ) \\ ) " , operators. toNot)
150
-
151
- var correctedString : String ?
176
+ let toPattern = ( " expect \\ ( \( anything) \\ ) \\ .to \\ ( \( name) \\ ( \( anything) \\ ) \\ ) " , predicateDescription. to)
177
+ let toNotPattern = ( " expect \\ ( \( anything) \\ ) \\ .toNot \\ ( \( name) \\ ( \( anything) \\ ) \\ ) " , predicateDescription. toNot)
152
178
153
179
for case let ( pattern, operatorString? ) in [ toPattern, toNotPattern] {
154
180
let expression = regex ( pattern)
155
- if !expression. matches ( in: self , options: [ ] , range: range) . isEmpty {
156
- correctedString = expression. stringByReplacingMatches ( in: self ,
157
- options: [ ] ,
158
- range: range,
159
- withTemplate: " expect($1) \( operatorString) $2 " )
160
- break
181
+ guard !expression. matches ( in: self , options: [ ] , range: range) . isEmpty else {
182
+ continue
183
+ }
184
+
185
+ let valueReplacementPattern : String
186
+ switch predicateDescription. arity {
187
+ case . nullary( let analogueValue) :
188
+ valueReplacementPattern = analogueValue
189
+ case . withArguments:
190
+ valueReplacementPattern = " $2 "
161
191
}
192
+
193
+ let replacementPattern = " expect($1) \( operatorString) \( valueReplacementPattern) "
194
+
195
+ return expression. stringByReplacingMatches ( in: self ,
196
+ options: [ ] ,
197
+ range: range,
198
+ withTemplate: replacementPattern)
162
199
}
163
200
164
- return correctedString
201
+ return nil
165
202
}
166
203
}
0 commit comments