matchers 0.1.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/matcher/assertions.rb +19 -0
- data/lib/matcher/autoload.rb +5 -0
- data/lib/matcher/base.rb +183 -0
- data/lib/matcher/compatibility.rb +34 -0
- data/lib/matcher/debug.rb +62 -0
- data/lib/matcher/dsl/builder.rb +99 -0
- data/lib/matcher/dsl/chain.rb +84 -0
- data/lib/matcher/dsl/expression_dsl.rb +306 -0
- data/lib/matcher/dsl/matcher_dsl.rb +5 -0
- data/lib/matcher/dsl/optional.rb +82 -0
- data/lib/matcher/dsl/optional_chain.rb +24 -0
- data/lib/matcher/dsl/others.rb +28 -0
- data/lib/matcher/errors/and_error.rb +88 -0
- data/lib/matcher/errors/boolean_collector.rb +51 -0
- data/lib/matcher/errors/element_error.rb +24 -0
- data/lib/matcher/errors/empty_error.rb +23 -0
- data/lib/matcher/errors/error.rb +39 -0
- data/lib/matcher/errors/error_collector.rb +100 -0
- data/lib/matcher/errors/nested_error.rb +98 -0
- data/lib/matcher/errors/or_error.rb +88 -0
- data/lib/matcher/expression_cache.rb +57 -0
- data/lib/matcher/expression_labeler.rb +96 -0
- data/lib/matcher/expressions/array_expression.rb +45 -0
- data/lib/matcher/expressions/block.rb +189 -0
- data/lib/matcher/expressions/call.rb +307 -0
- data/lib/matcher/expressions/call_error.rb +45 -0
- data/lib/matcher/expressions/constant.rb +53 -0
- data/lib/matcher/expressions/expression.rb +237 -0
- data/lib/matcher/expressions/expression_walker.rb +77 -0
- data/lib/matcher/expressions/hash_expression.rb +59 -0
- data/lib/matcher/expressions/proc_expression.rb +96 -0
- data/lib/matcher/expressions/range_expression.rb +65 -0
- data/lib/matcher/expressions/recorder.rb +136 -0
- data/lib/matcher/expressions/rescue_last_error_expression.rb +49 -0
- data/lib/matcher/expressions/set_expression.rb +45 -0
- data/lib/matcher/expressions/string_expression.rb +53 -0
- data/lib/matcher/expressions/symbol_proc.rb +53 -0
- data/lib/matcher/expressions/variable.rb +87 -0
- data/lib/matcher/hash_stack.rb +52 -0
- data/lib/matcher/list.rb +102 -0
- data/lib/matcher/markers.rb +7 -0
- data/lib/matcher/matcher_cache.rb +18 -0
- data/lib/matcher/matchers/all_matcher.rb +60 -0
- data/lib/matcher/matchers/always_matcher.rb +34 -0
- data/lib/matcher/matchers/any_matcher.rb +70 -0
- data/lib/matcher/matchers/array_matcher.rb +72 -0
- data/lib/matcher/matchers/block_matcher.rb +61 -0
- data/lib/matcher/matchers/boolean_matcher.rb +37 -0
- data/lib/matcher/matchers/dig_matcher.rb +149 -0
- data/lib/matcher/matchers/each_matcher.rb +85 -0
- data/lib/matcher/matchers/each_pair_matcher.rb +119 -0
- data/lib/matcher/matchers/equal_matcher.rb +198 -0
- data/lib/matcher/matchers/equal_set_matcher.rb +112 -0
- data/lib/matcher/matchers/expression_matcher.rb +69 -0
- data/lib/matcher/matchers/filter_matcher.rb +115 -0
- data/lib/matcher/matchers/hash_matcher.rb +315 -0
- data/lib/matcher/matchers/imply_matcher.rb +83 -0
- data/lib/matcher/matchers/imply_some_matcher.rb +116 -0
- data/lib/matcher/matchers/index_by_matcher.rb +177 -0
- data/lib/matcher/matchers/inline_matcher.rb +101 -0
- data/lib/matcher/matchers/keys_matcher.rb +131 -0
- data/lib/matcher/matchers/kind_of_matcher.rb +35 -0
- data/lib/matcher/matchers/lazy_all_matcher.rb +69 -0
- data/lib/matcher/matchers/lazy_any_matcher.rb +69 -0
- data/lib/matcher/matchers/let_matcher.rb +73 -0
- data/lib/matcher/matchers/map_matcher.rb +148 -0
- data/lib/matcher/matchers/negated_array_matcher.rb +38 -0
- data/lib/matcher/matchers/negated_each_matcher.rb +36 -0
- data/lib/matcher/matchers/negated_each_pair_matcher.rb +38 -0
- data/lib/matcher/matchers/negated_imply_some_matcher.rb +46 -0
- data/lib/matcher/matchers/negated_matcher.rb +25 -0
- data/lib/matcher/matchers/negated_project_matcher.rb +31 -0
- data/lib/matcher/matchers/never_matcher.rb +35 -0
- data/lib/matcher/matchers/one_matcher.rb +68 -0
- data/lib/matcher/matchers/optional_matcher.rb +38 -0
- data/lib/matcher/matchers/parse_float_matcher.rb +86 -0
- data/lib/matcher/matchers/parse_integer_matcher.rb +101 -0
- data/lib/matcher/matchers/parse_iso8601_helper.rb +41 -0
- data/lib/matcher/matchers/parse_iso8601_matcher.rb +52 -0
- data/lib/matcher/matchers/parse_json_helper.rb +43 -0
- data/lib/matcher/matchers/parse_json_matcher.rb +59 -0
- data/lib/matcher/matchers/project_matcher.rb +72 -0
- data/lib/matcher/matchers/raises_matcher.rb +131 -0
- data/lib/matcher/matchers/range_matcher.rb +50 -0
- data/lib/matcher/matchers/reference_matcher.rb +213 -0
- data/lib/matcher/matchers/reference_matcher_collection.rb +57 -0
- data/lib/matcher/matchers/regexp_matcher.rb +86 -0
- data/lib/matcher/messages/expected_phrasing.rb +355 -0
- data/lib/matcher/messages/message.rb +104 -0
- data/lib/matcher/messages/message_builder.rb +35 -0
- data/lib/matcher/messages/message_rules.rb +240 -0
- data/lib/matcher/messages/namespaced_message_builder.rb +19 -0
- data/lib/matcher/messages/phrasing.rb +59 -0
- data/lib/matcher/messages/standard_message_builder.rb +105 -0
- data/lib/matcher/patterns/ast_mapping.rb +42 -0
- data/lib/matcher/patterns/capture_hole.rb +33 -0
- data/lib/matcher/patterns/constant_hole.rb +14 -0
- data/lib/matcher/patterns/hole.rb +30 -0
- data/lib/matcher/patterns/method_hole.rb +62 -0
- data/lib/matcher/patterns/pattern.rb +104 -0
- data/lib/matcher/patterns/pattern_building.rb +39 -0
- data/lib/matcher/patterns/pattern_capture.rb +11 -0
- data/lib/matcher/patterns/pattern_match.rb +29 -0
- data/lib/matcher/patterns/variable_hole.rb +14 -0
- data/lib/matcher/reporter.rb +103 -0
- data/lib/matcher/rules/message_factory.rb +26 -0
- data/lib/matcher/rules/message_rule.rb +18 -0
- data/lib/matcher/rules/message_rule_context.rb +26 -0
- data/lib/matcher/rules/rule_builder.rb +29 -0
- data/lib/matcher/rules/rule_set.rb +57 -0
- data/lib/matcher/rules/transform_builder.rb +24 -0
- data/lib/matcher/rules/transform_mapping.rb +5 -0
- data/lib/matcher/rules/transform_rule.rb +21 -0
- data/lib/matcher/state.rb +40 -0
- data/lib/matcher/testing/error_builder.rb +62 -0
- data/lib/matcher/testing/error_checker.rb +514 -0
- data/lib/matcher/testing/error_testing.rb +37 -0
- data/lib/matcher/testing/pattern_testing.rb +11 -0
- data/lib/matcher/testing/pattern_testing_scope.rb +34 -0
- data/lib/matcher/testing.rb +107 -0
- data/lib/matcher/undefined.rb +10 -0
- data/lib/matcher/utils/mapping_utils.rb +61 -0
- data/lib/matcher/utils.rb +72 -0
- data/lib/matcher/version.rb +5 -0
- data/lib/matcher.rb +346 -0
- metadata +174 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class ExpectedPhrasing < Phrasing
|
|
5
|
+
define(:truthy) do
|
|
6
|
+
verb = verb(negated: true)
|
|
7
|
+
truthy_or_falsy = negated ? "truthy" : "falsy"
|
|
8
|
+
|
|
9
|
+
"#{verb} a #{truthy_or_falsy} value but got #{actual.inspect}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
define(:same) do |object|
|
|
13
|
+
"#{verb} same as #{object.inspect} (id=#{object.object_id})" \
|
|
14
|
+
"#{" but got #{actual.inspect} (id=#{actual.object_id})" if negated}"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
define(:equal) do |value|
|
|
18
|
+
if negated
|
|
19
|
+
"#{verb} #{value.inspect} but got #{actual.inspect}"
|
|
20
|
+
else
|
|
21
|
+
"#{verb} #{actual.inspect}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
define(:less_than) do |operand|
|
|
26
|
+
if negated || (actual <=> operand).nil?
|
|
27
|
+
"#{verb} a value < #{operand.inspect} but got #{actual.inspect}"
|
|
28
|
+
else
|
|
29
|
+
phrase_negated(:greater_than_or_equal, operand)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
define(:greater_than) do |operand|
|
|
34
|
+
if negated || (actual <=> operand).nil?
|
|
35
|
+
"#{verb} a value > #{operand.inspect} but got #{actual.inspect}"
|
|
36
|
+
else
|
|
37
|
+
phrase_negated(:less_than_or_equal, operand)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
define(:less_than_or_equal) do |operand|
|
|
42
|
+
if negated || (actual <=> operand).nil?
|
|
43
|
+
"#{verb} a value <= #{operand.inspect} but got #{actual.inspect}"
|
|
44
|
+
else
|
|
45
|
+
phrase_negated(:greater_than, operand)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
define(:greater_than_or_equal) do |operand|
|
|
50
|
+
if negated || (actual <=> operand).nil?
|
|
51
|
+
"#{verb} a value >= #{operand.inspect} but got #{actual.inspect}"
|
|
52
|
+
else
|
|
53
|
+
phrase_negated(:less_than, operand)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
define(:comparable_to) do |operand|
|
|
58
|
+
"#{verb} a value comparable to #{operand.inspect} " \
|
|
59
|
+
"but got #{actual.inspect}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
define(:between) do |min, max, exclude_end: false|
|
|
63
|
+
"#{verb} value to be between #{min.inspect} and " \
|
|
64
|
+
"#{max.inspect}#{' (exclusive)' if exclude_end} " \
|
|
65
|
+
"but got #{actual.inspect}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
define(:length_of) do |exp, act|
|
|
69
|
+
"#{verb} length of #{exp}#{" but was #{act}" if negated}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
define(:having_key) do |key|
|
|
73
|
+
"#{verb} to include key #{key.inspect} but got #{actual.inspect}"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
define(:having_index) do |index|
|
|
77
|
+
"#{verb} to have index #{index.inspect} but got #{actual.inspect}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
define(:exist) do
|
|
81
|
+
"#{verb} to exist#{" but got #{actual.inspect}" unless negated}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
define(:in) do |collection|
|
|
85
|
+
"#{verb} object to be included in #{collection.inspect} " \
|
|
86
|
+
"but got #{actual.inspect}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
define(:including) do |item|
|
|
90
|
+
"#{verb} #{item.inspect} to be included but got #{actual.inspect}"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
define(:duplicate) do |original_index|
|
|
94
|
+
"#{verb} duplicate originally at index #{original_index} " \
|
|
95
|
+
"but got #{actual.inspect}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
define(:duplicate_by) do |expression, value, original_index|
|
|
99
|
+
"#{verb} duplicate by #{expression.inspect}=#{value.inspect} " \
|
|
100
|
+
"originally at index #{original_index} but got #{actual.inspect}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
define(:matching) do |pattern|
|
|
104
|
+
"#{verb} value to match #{pattern.inspect} but got #{actual.inspect}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
define(:valid_format) do |format|
|
|
108
|
+
"#{verb} a valid #{format} string but got #{actual.inspect}"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
define(:instance_of) do |klass|
|
|
112
|
+
"#{verb} an instance of #{klass} but got #{actual.inspect}"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
define(:kind_of) do |klass|
|
|
116
|
+
"#{verb} a kind of #{klass} but got #{actual.inspect}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
define(:responding_to) do |method|
|
|
120
|
+
"#{verb} an object responding to `#{method}' but got #{actual.inspect}"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
define(:predicate) do |predicate|
|
|
124
|
+
predicate = predicate.to_s.delete_suffix("?")
|
|
125
|
+
|
|
126
|
+
"#{verb} value to be #{predicate} but got #{actual.inspect}"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
define(:described_by) do |description|
|
|
130
|
+
"#{verb} #{description} but got #{actual.inspect}"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
namespace(:expression) do
|
|
134
|
+
define(:truthy) do |expression, value, given|
|
|
135
|
+
verb = verb(negated: true)
|
|
136
|
+
truthy_or_falsy = negated ? "truthy" : "falsy"
|
|
137
|
+
|
|
138
|
+
"#{verb} #{expression} to be #{truthy_or_falsy} " \
|
|
139
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
define(:same) do |left_expression, right_expression, left, right, given|
|
|
143
|
+
"#{verb} #{left_expression} to be same as #{right_expression} " \
|
|
144
|
+
"but got #{left.inspect} (id=#{left.object_id})" \
|
|
145
|
+
"#{" and #{right.inspect} (id=#{right.object_id})" if negated}" \
|
|
146
|
+
"#{where_text(given, left_expression, right_expression)}"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
negated_comparisons =
|
|
150
|
+
{ :== => :!=, :!= => :==, :< => :>=, :> => :<=, :<= => :>, :>= => :< }
|
|
151
|
+
|
|
152
|
+
define(:comparison) do |expression, left, right, given|
|
|
153
|
+
can_negate = !negated &&
|
|
154
|
+
(method = negated_comparisons[expression.method]) &&
|
|
155
|
+
(%i[== !=].include?(method) || left <=> right)
|
|
156
|
+
|
|
157
|
+
verb = if can_negate
|
|
158
|
+
expression = Call.new(
|
|
159
|
+
expression.receiver,
|
|
160
|
+
method,
|
|
161
|
+
expression.args,
|
|
162
|
+
expression.kwargs,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
verb(negated: true)
|
|
166
|
+
else
|
|
167
|
+
self.verb
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
"#{verb} #{expression} but got " \
|
|
171
|
+
"#{left.inspect} #{expression.method} #{right.inspect}" \
|
|
172
|
+
"#{where_text(given, expression.receiver, expression.args[0])}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
define(:comparable_to) do |expression, value, operand, given|
|
|
176
|
+
"#{verb} #{expression} to be comparable to #{operand.inspect} " \
|
|
177
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
define(:between) do |expression, value, min, max, given|
|
|
181
|
+
"#{verb} #{expression} to be between " \
|
|
182
|
+
"#{min.inspect} and #{max.inspect} " \
|
|
183
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
define(:length_of) do |expression, _value, exp, act, given|
|
|
187
|
+
"#{verb} #{expression} to have length of #{exp}" \
|
|
188
|
+
"#{" but was #{act}" if negated}#{where_text(given, expression)}"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
define(:having_key) do |expression, value, key, given|
|
|
192
|
+
"#{verb} #{expression} to include key #{key.inspect} " \
|
|
193
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
define(:in) do |expression, value, collection, given|
|
|
197
|
+
"#{verb} #{expression} to be included in #{collection.inspect} " \
|
|
198
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
define(:including) do |expression, value, item, given|
|
|
202
|
+
"#{verb} #{expression} to include #{item.inspect} " \
|
|
203
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
define(:matching) do |expression, value, pattern, given|
|
|
207
|
+
"#{verb} #{expression} to match #{pattern.inspect} " \
|
|
208
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
match_at_words = {
|
|
212
|
+
:== => "at",
|
|
213
|
+
:!= => "not at",
|
|
214
|
+
:< => "before",
|
|
215
|
+
:> => "after",
|
|
216
|
+
:<= => "at or before",
|
|
217
|
+
:>= => "at or after",
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
define(:match_at) do |expression, value, pattern, position, comparison,
|
|
221
|
+
operand, given|
|
|
222
|
+
|
|
223
|
+
comparison_word = match_at_words[comparison]
|
|
224
|
+
|
|
225
|
+
message = String.new
|
|
226
|
+
message << "#{verb} #{expression} to match " \
|
|
227
|
+
"#{pattern.inspect} #{comparison_word} #{operand} "
|
|
228
|
+
message << "but was at #{position} " if
|
|
229
|
+
operand != position || comparison != (negated ? :!= : :==)
|
|
230
|
+
message << "for #{value.inspect}#{where_text(given, expression)}"
|
|
231
|
+
|
|
232
|
+
message
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
define(:instance_of) do |expression, value, klass, given|
|
|
236
|
+
"#{verb} #{expression} to be an instance of #{klass} " \
|
|
237
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
define(:kind_of) do |expression, value, klass, given|
|
|
241
|
+
"#{verb} #{expression} to be a kind of #{klass} " \
|
|
242
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
define(:responding_to) do |expression, value, method, given|
|
|
246
|
+
"#{verb} #{expression} to respond to `#{method}' " \
|
|
247
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
define(:predicate) do |expression, value, predicate, given|
|
|
251
|
+
predicate = predicate.to_s.delete_suffix("?")
|
|
252
|
+
|
|
253
|
+
"#{verb} #{expression} to be #{predicate} " \
|
|
254
|
+
"but got #{value.inspect}#{where_text(given, expression)}"
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
define(:raising) do |expression, error, given|
|
|
258
|
+
error_class = error.is_a?(Class) ? error : error.class
|
|
259
|
+
where = where_text(given, expression)
|
|
260
|
+
|
|
261
|
+
text = "#{verb} #{expression} to raise #{error_class}#{where}"
|
|
262
|
+
text += ": #{error.message}" if error.is_a?(Exception)
|
|
263
|
+
|
|
264
|
+
text
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
namespace(:negated) do
|
|
269
|
+
define(:valid) do |matcher|
|
|
270
|
+
"#{verb} #{matcher} to be valid but got #{actual.inspect}"
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
namespace(:block) do
|
|
275
|
+
define(:satisfied) do |block_location|
|
|
276
|
+
"#{verb} to satisfy condition #{block_location} " \
|
|
277
|
+
"but got #{actual.inspect}"
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
namespace(:imply_some) do
|
|
282
|
+
def x_conditions(count)
|
|
283
|
+
case count
|
|
284
|
+
when :any
|
|
285
|
+
"any condition"
|
|
286
|
+
when 1
|
|
287
|
+
"one condition"
|
|
288
|
+
else
|
|
289
|
+
"#{count} conditions"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
private :x_conditions
|
|
293
|
+
|
|
294
|
+
define(:no_condition_satisfied) do |conditions, count|
|
|
295
|
+
"#{negated_verb} to satisfy #{x_conditions(count)} " \
|
|
296
|
+
"but got #{actual.inspect} and met none of these: #{join(conditions)}"
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
define(:x_conditions_satisfied) do |conditions, count|
|
|
300
|
+
"#{negated_verb} to satisfy #{x_conditions(count)} " \
|
|
301
|
+
"but got #{actual.inspect} and met these: #{join(conditions)}"
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
namespace(:reference) do
|
|
306
|
+
define(:cyclic) do
|
|
307
|
+
"#{verb} a cyclic structure" \
|
|
308
|
+
"#{' but actual has already been visited' unless negated}"
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
define(:failed_from_cache) do
|
|
312
|
+
"actual has already failed before"
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
namespace(:set) do
|
|
317
|
+
define(:equal) do |set|
|
|
318
|
+
"#{verb} object to be an equal set to #{set.inspect} " \
|
|
319
|
+
"but got #{actual.inspect}"
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
private
|
|
324
|
+
|
|
325
|
+
def verb(negated: self.negated)
|
|
326
|
+
# A message says what actual is but expected says what it is not. That's
|
|
327
|
+
# why the verb is counter-intuitively negated.
|
|
328
|
+
|
|
329
|
+
negated ? "expected" : "did not expect"
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def negated_verb
|
|
333
|
+
verb(negated: !negated)
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def join(objects)
|
|
337
|
+
objects.join(", ")
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def where_text(values, *expressions)
|
|
341
|
+
return "" if values.empty?
|
|
342
|
+
|
|
343
|
+
except = expressions.filter_map { _1.symbol if _1.is_a?(Variable) }
|
|
344
|
+
symbols = expressions.flat_map(&:variables).uniq - except
|
|
345
|
+
|
|
346
|
+
return "" if symbols.empty?
|
|
347
|
+
|
|
348
|
+
list = symbols
|
|
349
|
+
.map { "#{_1} = #{values.fetch(_1).inspect}" }
|
|
350
|
+
.join(", ")
|
|
351
|
+
|
|
352
|
+
", where #{list}"
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class Message
|
|
5
|
+
attr_reader :key, :negated, :actual, :args, :kwargs
|
|
6
|
+
|
|
7
|
+
def initialize(key, negated, actual, *args, **kwargs)
|
|
8
|
+
@key = key
|
|
9
|
+
@negated = negated
|
|
10
|
+
@actual = actual
|
|
11
|
+
@args = args
|
|
12
|
+
@kwargs = kwargs
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def negate!
|
|
16
|
+
@negated = !@negated
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ==(other)
|
|
20
|
+
return true if equal?(other)
|
|
21
|
+
|
|
22
|
+
other.instance_of?(Message) &&
|
|
23
|
+
@key.eql?(other.key) &&
|
|
24
|
+
@negated == other.negated &&
|
|
25
|
+
@actual.eql?(other.actual) &&
|
|
26
|
+
@args.eql?(other.args) &&
|
|
27
|
+
@kwargs.eql?(other.kwargs)
|
|
28
|
+
end
|
|
29
|
+
alias eql? ==
|
|
30
|
+
|
|
31
|
+
def hash
|
|
32
|
+
@hash ||= [self.class, @key, @negated, @actual, @args, @kwargs].hash
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def namespace
|
|
36
|
+
@key.is_a?(Array) ? @key[0] : nil
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_standard
|
|
40
|
+
return self if namespace != :expression
|
|
41
|
+
|
|
42
|
+
key = @key[1]
|
|
43
|
+
|
|
44
|
+
case key
|
|
45
|
+
when :truthy
|
|
46
|
+
_expr, value = @args
|
|
47
|
+
Message.new(key, @negated, value)
|
|
48
|
+
when :same
|
|
49
|
+
_l_expr, _r_expr, left, right = @args
|
|
50
|
+
Message.new(:same, @negated, left, right)
|
|
51
|
+
when :comparable_to, :having_key, :in, :including, :matching,
|
|
52
|
+
:instance_of, :kind_of, :responding_to, :predicate
|
|
53
|
+
|
|
54
|
+
_expr, value, operand = @args
|
|
55
|
+
Message.new(key, @negated, value, operand)
|
|
56
|
+
when :between, :length_of
|
|
57
|
+
_expr, value, operand1, operand2 = @args
|
|
58
|
+
Message.new(key, @negated, value, operand1, operand2)
|
|
59
|
+
when :comparison
|
|
60
|
+
expr, left, right = @args
|
|
61
|
+
|
|
62
|
+
case expr.method
|
|
63
|
+
when :==
|
|
64
|
+
Message.new(:equal, @negated, left, right)
|
|
65
|
+
when :!=
|
|
66
|
+
Message.new(:equal, !@negated, left, right)
|
|
67
|
+
when :<
|
|
68
|
+
Message.new(:less_than, @negated, left, right)
|
|
69
|
+
when :>
|
|
70
|
+
Message.new(:greater_than, @negated, left, right)
|
|
71
|
+
when :<=
|
|
72
|
+
Message.new(:less_than_or_equal, @negated, left, right)
|
|
73
|
+
when :>=
|
|
74
|
+
Message.new(:greater_than_or_equal, @negated, left, right)
|
|
75
|
+
else
|
|
76
|
+
raise "unexpected method: #{expr.method.inspect}"
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
self
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def to_s
|
|
84
|
+
if @key.is_a?(Array)
|
|
85
|
+
namespace, key = @key
|
|
86
|
+
else
|
|
87
|
+
key = @key
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
args_and_kwargs = @args.map(&:inspect) + @kwargs.map do |k, v|
|
|
91
|
+
k.is_a?(Symbol) ? "#{k}: #{v.inspect}" : "#{k.inspect} => #{v.inspect}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
string = "report(#{@actual.inspect})"
|
|
95
|
+
string += ".namespace(#{namespace.inspect})" if namespace
|
|
96
|
+
string += ".not" if @negated
|
|
97
|
+
string += ".#{key}"
|
|
98
|
+
string += "(#{args_and_kwargs.join(', ')})" unless args_and_kwargs.empty?
|
|
99
|
+
|
|
100
|
+
string
|
|
101
|
+
end
|
|
102
|
+
alias inspect to_s
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Matcher
|
|
4
|
+
class MessageBuilder
|
|
5
|
+
def initialize(negated, actual)
|
|
6
|
+
@negated = negated
|
|
7
|
+
@actual = actual
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def not
|
|
11
|
+
@negated = !@negated
|
|
12
|
+
self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def not_if(condition)
|
|
16
|
+
condition ? self.not : self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
protected
|
|
20
|
+
|
|
21
|
+
def message(key, *, **)
|
|
22
|
+
Message.new(key, @negated, @actual, *, **)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def method_missing(method, *, **)
|
|
28
|
+
message(method, *, **)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def respond_to_missing?(_name, _include_private = false)
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|