minicrest 1.0.18 → 1.0.20
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 +4 -4
- data/.yardopts +1 -0
- data/CHANGELOG.md +10 -1
- data/README.md +2 -627
- data/USAGE.md +670 -0
- data/lib/minicrest/value_matchers.rb +61 -0
- data/lib/minicrest/version.rb +1 -1
- data/lib/minicrest.rb +0 -1
- metadata +2 -2
- data/lib/minicrest/descends_from.rb +0 -64
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 58f5e87992e24bee1a51f8f51ce095394c64f6900b4dbbbb4bdbde2010432343
|
|
4
|
+
data.tar.gz: b5b8bc6eed685cbcd6e8b07292c141dcafcb10475e6162df7c54b4c736ccb434
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 277c1b9a9bd11b6443cd55ce20b3444a951cea80b0f1bda89c052dbf5bb2d0cfa36e01cc03c9532bacc7ca903b81912bba60442a1c017232237a2b1a9f67835a
|
|
7
|
+
data.tar.gz: 25adcc959dde84205306c2bd6d56d83164534b8607cfcd0f64716afec17da97b206d15e4202d861531b3092476e6a6febf2fc3c1b74c14bfd77d18e860d17a0e
|
data/.yardopts
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
## [1.0.
|
|
10
|
+
## [1.0.20] - 2026-01-18
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Reorganized documentation: extracted detailed usage into `USAGE.md` and added Table of Contents.
|
|
14
|
+
- Internal refactoring: moved `DescendsFrom` to `value_matchers.rb` and consolidated type matchers.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- Added missing tests for `NilValue`, `Truthy`, `Falsy`, and `InstanceOf` matchers.
|
|
18
|
+
|
|
19
|
+
## [1.0.0 - 1.0.19] - 2026-01-18
|
|
11
20
|
|
|
12
21
|
- Housekeeping: automate CI and release workflows
|
|
13
22
|
|
data/README.md
CHANGED
|
@@ -46,6 +46,8 @@ class MyTest < Minitest::Test
|
|
|
46
46
|
end
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
See [USAGE.md](USAGE.md) for more details and a full list of available matchers.
|
|
50
|
+
|
|
49
51
|
## Running Tests
|
|
50
52
|
|
|
51
53
|
To run the library's own tests:
|
|
@@ -54,633 +56,6 @@ To run the library's own tests:
|
|
|
54
56
|
rake test
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
## Core Matchers
|
|
58
|
-
|
|
59
|
-
### Value Equality
|
|
60
|
-
|
|
61
|
-
```ruby
|
|
62
|
-
# Simple values
|
|
63
|
-
assert_that("hello").equals("hello")
|
|
64
|
-
|
|
65
|
-
# Arrays with deep comparison
|
|
66
|
-
assert_that([1, [2, 3]]).equals([1, [2, 3]])
|
|
67
|
-
|
|
68
|
-
# Hashes with deep comparison
|
|
69
|
-
assert_that({ user: { name: "Alice" } }).equals({ user: { name: "Alice" } })
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Reference Equality
|
|
73
|
-
|
|
74
|
-
Test that two variables point to the same object:
|
|
75
|
-
|
|
76
|
-
```ruby
|
|
77
|
-
obj = Object.new
|
|
78
|
-
assert_that(obj).is(obj)
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Negation
|
|
82
|
-
|
|
83
|
-
```ruby
|
|
84
|
-
assert_that(42).never(equals(0))
|
|
85
|
-
assert_that(nil).never(equals(false))
|
|
86
|
-
|
|
87
|
-
# Aliases for more natural flow
|
|
88
|
-
assert_that(42).is_not(0)
|
|
89
|
-
assert_that("hello").does_not(start_with("bye"))
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Placeholder Matching
|
|
93
|
-
|
|
94
|
-
Use `anything` when you don't care about a particular value:
|
|
95
|
-
|
|
96
|
-
```ruby
|
|
97
|
-
assert_that(some_value).is(anything)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Use `truthy` or `falsy` to match any truthy or falsy value in Ruby:
|
|
101
|
-
|
|
102
|
-
```ruby
|
|
103
|
-
assert_that(some_value).is(truthy)
|
|
104
|
-
assert_that(some_value).is(anything)
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Type and Method Matchers
|
|
108
|
-
|
|
109
|
-
### `is_a(type)` / `descends_from(type)`
|
|
110
|
-
|
|
111
|
-
Matches if the value is an instance of the expected type (including inheritance):
|
|
112
|
-
|
|
113
|
-
```ruby
|
|
114
|
-
assert_that("hello").matches(is_a(String))
|
|
115
|
-
assert_that(42).matches(descends_from(Integer))
|
|
116
|
-
assert_that([]).matches(is_a(Enumerable)) # works with modules
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### `instance_of(type)`
|
|
120
|
-
|
|
121
|
-
Matches if the value is an exact instance of the expected class (no inheritance):
|
|
122
|
-
|
|
123
|
-
```ruby
|
|
124
|
-
assert_that("hello").matches(instance_of(String))
|
|
125
|
-
assert_that(42).never(instance_of(Numeric)) # Integer is a Numeric, but not exactly InstanceOf Numeric
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### `responds_to(*methods)`
|
|
129
|
-
|
|
130
|
-
Matches if the value responds to all specified methods:
|
|
131
|
-
|
|
132
|
-
```ruby
|
|
133
|
-
assert_that("hello").matches(responds_to(:upcase))
|
|
134
|
-
assert_that([]).matches(responds_to(:push, :pop))
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
## Value Matchers
|
|
138
|
-
|
|
139
|
-
### `nil_value`
|
|
140
|
-
|
|
141
|
-
Matches if the value is `nil`:
|
|
142
|
-
|
|
143
|
-
```ruby
|
|
144
|
-
assert_that(nil).matches(nil_value)
|
|
145
|
-
assert_that(42).never(nil_value)
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### `truthy`
|
|
149
|
-
|
|
150
|
-
Matches if the value is considered true (anything except `nil` or `false`):
|
|
151
|
-
|
|
152
|
-
```ruby
|
|
153
|
-
assert_that(true).matches(truthy)
|
|
154
|
-
assert_that(42).matches(truthy)
|
|
155
|
-
assert_that("hello").matches(truthy)
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### `falsy`
|
|
159
|
-
|
|
160
|
-
Matches if the value is considered false (`nil` or `false`):
|
|
161
|
-
|
|
162
|
-
```ruby
|
|
163
|
-
assert_that(false).matches(falsy)
|
|
164
|
-
assert_that(nil).matches(falsy)
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## String Matchers
|
|
168
|
-
|
|
169
|
-
### `starts_with(prefix)`
|
|
170
|
-
|
|
171
|
-
```ruby
|
|
172
|
-
assert_that("hello world").matches(starts_with("hello"))
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### `ends_with(suffix)`
|
|
176
|
-
|
|
177
|
-
```ruby
|
|
178
|
-
assert_that("hello world").matches(ends_with("world"))
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### `matches_pattern(regex)`
|
|
182
|
-
|
|
183
|
-
```ruby
|
|
184
|
-
assert_that("hello123").matches(matches_pattern(/\d+/))
|
|
185
|
-
assert_that("test@example.com").matches(matches_pattern(/\A[\w.]+@[\w.]+\z/))
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### `blank`
|
|
189
|
-
|
|
190
|
-
Matches empty or whitespace-only strings:
|
|
191
|
-
|
|
192
|
-
```ruby
|
|
193
|
-
assert_that("").matches(blank)
|
|
194
|
-
assert_that(" ").matches(blank)
|
|
195
|
-
assert_that("\t\n").matches(blank)
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Size and Emptiness Matchers
|
|
199
|
-
|
|
200
|
-
### `empty`
|
|
201
|
-
|
|
202
|
-
Matches empty strings, arrays, or hashes:
|
|
203
|
-
|
|
204
|
-
```ruby
|
|
205
|
-
assert_that("").matches(empty)
|
|
206
|
-
assert_that([]).matches(empty)
|
|
207
|
-
assert_that({}).matches(empty)
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### `has_size(expected)`
|
|
211
|
-
|
|
212
|
-
Matches values with a specific size:
|
|
213
|
-
|
|
214
|
-
```ruby
|
|
215
|
-
assert_that("hello").matches(has_size(5))
|
|
216
|
-
assert_that([1, 2, 3]).matches(has_size(3))
|
|
217
|
-
assert_that({ a: 1, b: 2 }).matches(has_size(2))
|
|
218
|
-
|
|
219
|
-
# Can use matchers for flexible size checks
|
|
220
|
-
assert_that([1, 2, 3]).matches(has_size(is_greater_than(2)))
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
## Numeric Comparison Matchers
|
|
224
|
-
|
|
225
|
-
### `is_greater_than(expected)`
|
|
226
|
-
|
|
227
|
-
```ruby
|
|
228
|
-
assert_that(5).matches(is_greater_than(3))
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### `is_greater_than_or_equal_to(expected)`
|
|
232
|
-
|
|
233
|
-
```ruby
|
|
234
|
-
assert_that(5).matches(is_greater_than_or_equal_to(5))
|
|
235
|
-
assert_that(6).matches(is_greater_than_or_equal_to(5))
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### `is_less_than(expected)`
|
|
239
|
-
|
|
240
|
-
```ruby
|
|
241
|
-
assert_that(3).matches(is_less_than(5))
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
### `is_less_than_or_equal_to(expected)`
|
|
245
|
-
|
|
246
|
-
```ruby
|
|
247
|
-
assert_that(5).matches(is_less_than_or_equal_to(5))
|
|
248
|
-
assert_that(4).matches(is_less_than_or_equal_to(5))
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### `between(min, max, exclusive: false)`
|
|
252
|
-
|
|
253
|
-
Matches if the value is within the range:
|
|
254
|
-
|
|
255
|
-
```ruby
|
|
256
|
-
assert_that(5).matches(between(1, 10))
|
|
257
|
-
assert_that(10).never(between(1, 10, exclusive: true))
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### `is_close_to(expected, delta)`
|
|
261
|
-
|
|
262
|
-
Floating-point equality with tolerance:
|
|
263
|
-
|
|
264
|
-
```ruby
|
|
265
|
-
assert_that(3.14159).matches(is_close_to(3.14, 0.01))
|
|
266
|
-
assert_that(10.0).matches(is_close_to(10.5, 0.5))
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
## Collection Content Matchers
|
|
270
|
-
|
|
271
|
-
### `includes(*items)`
|
|
272
|
-
|
|
273
|
-
Matches if the value contains all specified items:
|
|
274
|
-
|
|
275
|
-
```ruby
|
|
276
|
-
# Strings: contains substrings
|
|
277
|
-
assert_that("hello world").matches(includes("hello", "world"))
|
|
278
|
-
|
|
279
|
-
# Arrays: contains elements
|
|
280
|
-
assert_that([1, 2, 3, 4]).matches(includes(2, 4))
|
|
281
|
-
|
|
282
|
-
# Hashes: contains key-value pairs
|
|
283
|
-
assert_that({ a: 1, b: 2, c: 3 }).matches(includes(a: 1, c: 3))
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
### `has_key(*keys)`
|
|
287
|
-
|
|
288
|
-
Matches if the hash contains all specified keys:
|
|
289
|
-
|
|
290
|
-
```ruby
|
|
291
|
-
assert_that({ a: 1, b: 2 }).matches(has_key(:a))
|
|
292
|
-
assert_that({ a: 1, b: 2 }).matches(has_key(:a, :b))
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### `has_value(*values)`
|
|
296
|
-
|
|
297
|
-
Matches if the hash contains all specified values:
|
|
298
|
-
|
|
299
|
-
```ruby
|
|
300
|
-
assert_that({ a: 1, b: 2 }).matches(has_value(1))
|
|
301
|
-
assert_that({ a: 1, b: 2 }).matches(has_value(1, 2))
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### `contains(*items)`
|
|
305
|
-
|
|
306
|
-
Matches if the collection contains exactly the specified items in any order:
|
|
307
|
-
|
|
308
|
-
```ruby
|
|
309
|
-
assert_that([3, 1, 2]).matches(contains(1, 2, 3))
|
|
310
|
-
assert_that({ b: 2, a: 1 }).matches(contains(a: 1, b: 2))
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### `contains_exactly(*items)`
|
|
314
|
-
|
|
315
|
-
Matches if the array contains exactly the specified items in order:
|
|
316
|
-
|
|
317
|
-
```ruby
|
|
318
|
-
assert_that([1, 2, 3]).matches(contains_exactly(1, 2, 3))
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
## Collection Item Matchers
|
|
322
|
-
|
|
323
|
-
### `all_items(matcher)`
|
|
324
|
-
|
|
325
|
-
Matches if all items in the collection match:
|
|
326
|
-
|
|
327
|
-
```ruby
|
|
328
|
-
assert_that([2, 4, 6]).matches(all_items(descends_from(Integer)))
|
|
329
|
-
assert_that([2, 4, 6]).matches(all_items(is_greater_than(0)))
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### `some_items(matcher)`
|
|
333
|
-
|
|
334
|
-
Matches if at least one item matches:
|
|
335
|
-
|
|
336
|
-
```ruby
|
|
337
|
-
assert_that([1, "two", 3]).matches(some_items(descends_from(String)))
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
### `no_items(matcher)`
|
|
341
|
-
|
|
342
|
-
Matches if no items match:
|
|
343
|
-
|
|
344
|
-
```ruby
|
|
345
|
-
assert_that([1, 2, 3]).matches(no_items(descends_from(String)))
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### `all_entries(matcher)` / `some_entry(matcher)` / `no_entry(matcher)`
|
|
349
|
-
|
|
350
|
-
Similar to item matchers, but specifically for hash entries (key-value pairs):
|
|
351
|
-
|
|
352
|
-
```ruby
|
|
353
|
-
# all_entries expects a matcher that works with [key, value] arrays
|
|
354
|
-
assert_that({ a: 1, b: 2 }).matches(all_entries(includes(:a, :b) | includes(1, 2)))
|
|
355
|
-
|
|
356
|
-
# You can also use a Proc for more complex entry matching
|
|
357
|
-
assert_that({ a: 1, b: 2 }).matches(some_entry(->(entry) { entry[1] > 1 }))
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
## Membership Matcher
|
|
361
|
-
|
|
362
|
-
### `is_in(collection)`
|
|
363
|
-
|
|
364
|
-
Matches if the value is present in the collection:
|
|
365
|
-
|
|
366
|
-
```ruby
|
|
367
|
-
assert_that(2).matches(is_in([1, 2, 3]))
|
|
368
|
-
assert_that(:a).matches(is_in({ a: 1, b: 2 })) # checks keys
|
|
369
|
-
assert_that("el").matches(is_in("hello")) # substring
|
|
370
|
-
assert_that(5).matches(is_in(1..10)) # ranges
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
## Object Attribute Matcher
|
|
374
|
-
|
|
375
|
-
### `has_attribute(name, matcher = nil)`
|
|
376
|
-
|
|
377
|
-
Matches if the object has the attribute, optionally checking its value:
|
|
378
|
-
|
|
379
|
-
```ruby
|
|
380
|
-
User = Struct.new(:name, :age)
|
|
381
|
-
|
|
382
|
-
user = User.new("Alice", 30)
|
|
383
|
-
|
|
384
|
-
assert_that(user).matches(has_attribute(:name))
|
|
385
|
-
assert_that(user).matches(has_attribute(:name, equals("Alice")))
|
|
386
|
-
assert_that(user).matches(has_attribute(:age, is_greater_than(18)))
|
|
387
|
-
|
|
388
|
-
# Also works with hashes
|
|
389
|
-
assert_that({ name: "Bob" }).matches(has_attribute(:name, equals("Bob")))
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
## Error Assertions
|
|
393
|
-
|
|
394
|
-
### `raises_error`
|
|
395
|
-
|
|
396
|
-
Assert that a block raises an error:
|
|
397
|
-
|
|
398
|
-
```ruby
|
|
399
|
-
# Any error
|
|
400
|
-
assert_that { raise "boom" }.raises_error
|
|
401
|
-
|
|
402
|
-
# Specific error class
|
|
403
|
-
assert_that { raise ArgumentError, "bad" }.raises_error(ArgumentError)
|
|
404
|
-
|
|
405
|
-
# Error class with message matcher
|
|
406
|
-
assert_that { raise ArgumentError, "bad input" }.raises_error(ArgumentError, includes("bad"))
|
|
407
|
-
assert_that { raise ArgumentError, "code: 123" }.raises_error(ArgumentError, matches_pattern(/\d+/))
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### `raises_nothing`
|
|
411
|
-
|
|
412
|
-
Assert that a block does not raise:
|
|
413
|
-
|
|
414
|
-
```ruby
|
|
415
|
-
assert_that { safe_operation }.raises_nothing
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
## Combining Matchers
|
|
419
|
-
|
|
420
|
-
Use `|` for OR and `&` for AND:
|
|
421
|
-
|
|
422
|
-
```ruby
|
|
423
|
-
# Either/or
|
|
424
|
-
assert_that(status).matches(equals(:success) | equals(:pending))
|
|
425
|
-
|
|
426
|
-
# Both conditions
|
|
427
|
-
assert_that(value).matches(is_greater_than(0) & is_less_than(100))
|
|
428
|
-
|
|
429
|
-
# Complex combinations
|
|
430
|
-
assert_that(result).matches(
|
|
431
|
-
(equals(1) | equals(2)) & never(equals(nil))
|
|
432
|
-
)
|
|
433
|
-
```
|
|
434
|
-
|
|
435
|
-
### Collection Combinators
|
|
436
|
-
|
|
437
|
-
```ruby
|
|
438
|
-
# All matchers must pass
|
|
439
|
-
assert_that(5).matches(all_of(is_greater_than(0), is_less_than(10)))
|
|
440
|
-
|
|
441
|
-
# No matchers should pass
|
|
442
|
-
assert_that(10).matches(none_of(equals(5), equals(6)))
|
|
443
|
-
|
|
444
|
-
# At least one matcher must pass
|
|
445
|
-
assert_that(5).matches(some_of(equals(5), equals(999)))
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
## Custom Matchers
|
|
449
|
-
|
|
450
|
-
Create your own matchers by subclassing `Minicrest::Matcher`:
|
|
451
|
-
|
|
452
|
-
```ruby
|
|
453
|
-
class BePositive < Minicrest::Matcher
|
|
454
|
-
def matches?(actual)
|
|
455
|
-
actual.is_a?(Numeric) && actual > 0
|
|
456
|
-
end
|
|
457
|
-
|
|
458
|
-
def description
|
|
459
|
-
"be positive"
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
def failure_message(actual)
|
|
463
|
-
"expected #{actual.inspect} to be a positive number"
|
|
464
|
-
end
|
|
465
|
-
end
|
|
466
|
-
|
|
467
|
-
# Register the matcher
|
|
468
|
-
Minicrest.register_matcher(:be_positive) { BePositive.new }
|
|
469
|
-
|
|
470
|
-
# Use in tests
|
|
471
|
-
assert_that(5).matches(be_positive)
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
### Parameterized Matchers
|
|
475
|
-
|
|
476
|
-
Matchers can accept arguments:
|
|
477
|
-
|
|
478
|
-
```ruby
|
|
479
|
-
class BeDivisibleBy < Minicrest::Matcher
|
|
480
|
-
def initialize(divisor)
|
|
481
|
-
super()
|
|
482
|
-
@divisor = divisor
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
def matches?(actual)
|
|
486
|
-
actual % @divisor == 0
|
|
487
|
-
end
|
|
488
|
-
|
|
489
|
-
def description
|
|
490
|
-
"be divisible by #{@divisor}"
|
|
491
|
-
end
|
|
492
|
-
end
|
|
493
|
-
|
|
494
|
-
Minicrest.register_matcher(:be_divisible_by) { |n| BeDivisibleBy.new(n) }
|
|
495
|
-
|
|
496
|
-
# Use in tests
|
|
497
|
-
assert_that(10).matches(be_divisible_by(5))
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
### Custom Matchers with Combinators
|
|
501
|
-
|
|
502
|
-
Registered matchers automatically work with all combinators:
|
|
503
|
-
|
|
504
|
-
```ruby
|
|
505
|
-
# With AND/OR operators
|
|
506
|
-
assert_that(10).matches(be_divisible_by(5) & be_divisible_by(2))
|
|
507
|
-
assert_that(10).matches(be_divisible_by(3) | be_divisible_by(5))
|
|
508
|
-
|
|
509
|
-
# With never()
|
|
510
|
-
assert_that(7).never(be_divisible_by(2))
|
|
511
|
-
|
|
512
|
-
# With all_of, some_of, none_of
|
|
513
|
-
assert_that(10).matches(all_of(be_positive, be_divisible_by(5)))
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
## Failure Messages
|
|
517
|
-
|
|
518
|
-
Minicrest provides detailed failure messages with diffs:
|
|
519
|
-
|
|
520
|
-
```ruby
|
|
521
|
-
assert_that({ name: "Bob" }).equals({ name: "Alice" })
|
|
522
|
-
```
|
|
523
|
-
|
|
524
|
-
Output:
|
|
525
|
-
|
|
526
|
-
```
|
|
527
|
-
expected {:name=>"Bob"}
|
|
528
|
-
to equal {:name=>"Alice"}
|
|
529
|
-
|
|
530
|
-
Diff:
|
|
531
|
-
key :name:
|
|
532
|
-
expected: "Alice"
|
|
533
|
-
actual: "Bob"
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
Array diffs show the index:
|
|
537
|
-
|
|
538
|
-
```ruby
|
|
539
|
-
assert_that([1, 2, 4]).equals([1, 2, 3])
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
Output:
|
|
543
|
-
|
|
544
|
-
```
|
|
545
|
-
expected [1, 2, 4]
|
|
546
|
-
to equal [1, 2, 3]
|
|
547
|
-
|
|
548
|
-
Diff:
|
|
549
|
-
[2]:
|
|
550
|
-
expected: 3
|
|
551
|
-
actual: 4
|
|
552
|
-
```
|
|
553
|
-
|
|
554
|
-
String diffs show the first difference:
|
|
555
|
-
|
|
556
|
-
```ruby
|
|
557
|
-
assert_that("hello").equals("hallo")
|
|
558
|
-
```
|
|
559
|
-
|
|
560
|
-
Output:
|
|
561
|
-
|
|
562
|
-
```
|
|
563
|
-
expected "hello"
|
|
564
|
-
to equal "hallo"
|
|
565
|
-
|
|
566
|
-
Diff:
|
|
567
|
-
at index 1:
|
|
568
|
-
expected: "a"
|
|
569
|
-
actual: "e"
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
## API Reference
|
|
573
|
-
|
|
574
|
-
### Assertions Module - Core
|
|
575
|
-
|
|
576
|
-
| Method | Description |
|
|
577
|
-
|--------|-------------|
|
|
578
|
-
| `assert_that(actual, message = nil)` | Entry point for value assertions |
|
|
579
|
-
| `assert_that { block }` | Entry point for block assertions |
|
|
580
|
-
| `equals(expected)` | Value equality matcher |
|
|
581
|
-
| `is(expected)` | Reference equality matcher (supports matchers) |
|
|
582
|
-
| `anything` | Matches any value |
|
|
583
|
-
| `never(matcher)` | Negates a matcher (aliases: `is_not`, `does_not`) |
|
|
584
|
-
|
|
585
|
-
### Assertions Module - Type & Method
|
|
586
|
-
|
|
587
|
-
| Method | Description |
|
|
588
|
-
|--------|-------------|
|
|
589
|
-
| `is_a(type)` | Type/class matcher (alias of `descends_from`) |
|
|
590
|
-
| `descends_from(type)` | Type/class matcher |
|
|
591
|
-
| `instance_of(type)` | Exact class matcher |
|
|
592
|
-
| `responds_to(*methods)` | Method presence matcher |
|
|
593
|
-
|
|
594
|
-
### Assertions Module - Values
|
|
595
|
-
|
|
596
|
-
| Method | Description |
|
|
597
|
-
|--------|-------------|
|
|
598
|
-
| `nil_value` | Matches `nil` |
|
|
599
|
-
| `truthy` | Matches non-nil, non-false values |
|
|
600
|
-
| `falsy` | Matches `nil` or `false` |
|
|
601
|
-
|
|
602
|
-
### Assertions Module - Strings
|
|
603
|
-
|
|
604
|
-
| Method | Description |
|
|
605
|
-
|--------|-------------|
|
|
606
|
-
| `starts_with(prefix)` | String prefix matcher |
|
|
607
|
-
| `ends_with(suffix)` | String suffix matcher |
|
|
608
|
-
| `matches_pattern(regex)` | Regex pattern matcher |
|
|
609
|
-
| `blank` | Blank string matcher |
|
|
610
|
-
|
|
611
|
-
### Assertions Module - Size & Emptiness
|
|
612
|
-
|
|
613
|
-
| Method | Description |
|
|
614
|
-
|--------|-------------|
|
|
615
|
-
| `empty` | Empty collection matcher |
|
|
616
|
-
| `has_size(expected)` | Size/length matcher |
|
|
617
|
-
|
|
618
|
-
### Assertions Module - Numeric
|
|
619
|
-
|
|
620
|
-
| Method | Description |
|
|
621
|
-
|--------|-------------|
|
|
622
|
-
| `is_greater_than(n)` | Greater than comparison |
|
|
623
|
-
| `is_greater_than_or_equal_to(n)` | Greater than or equal comparison |
|
|
624
|
-
| `is_less_than(n)` | Less than comparison |
|
|
625
|
-
| `is_less_than_or_equal_to(n)` | Less than or equal comparison |
|
|
626
|
-
| `between(min, max, exclusive: false)` | Range comparison |
|
|
627
|
-
| `is_close_to(n, delta)` | Floating-point tolerance |
|
|
628
|
-
|
|
629
|
-
### Assertions Module - Collections
|
|
630
|
-
|
|
631
|
-
| Method | Description |
|
|
632
|
-
|--------|-------------|
|
|
633
|
-
| `includes(*items)` | Partial containment |
|
|
634
|
-
| `has_key(*keys)` | Hash key presence |
|
|
635
|
-
| `has_value(*values)` | Hash value presence |
|
|
636
|
-
| `contains(*items)` | Exact items, any order |
|
|
637
|
-
| `contains_exactly(*items)` | Exact items, exact order |
|
|
638
|
-
| `all_items(matcher)` | All items match |
|
|
639
|
-
| `some_items(matcher)` | At least one matches |
|
|
640
|
-
| `no_items(matcher)` | No items match |
|
|
641
|
-
| `all_entries(matcher)` | All hash entries match |
|
|
642
|
-
| `some_entry(matcher)` | At least one entry matches |
|
|
643
|
-
| `no_entry(matcher)` | No entries match |
|
|
644
|
-
| `is_in(collection)` | Membership check |
|
|
645
|
-
|
|
646
|
-
### Assertions Module - Objects
|
|
647
|
-
|
|
648
|
-
| Method | Description |
|
|
649
|
-
|--------|-------------|
|
|
650
|
-
| `has_attribute(name, matcher = nil)` | Object attribute matcher |
|
|
651
|
-
|
|
652
|
-
### Assertions Module - Combinators
|
|
653
|
-
|
|
654
|
-
| Method | Description |
|
|
655
|
-
|--------|-------------|
|
|
656
|
-
| `all_of(*matchers)` | All matchers must match |
|
|
657
|
-
| `none_of(*matchers)` | No matcher should match |
|
|
658
|
-
| `some_of(*matchers)` | At least one must match |
|
|
659
|
-
|
|
660
|
-
### Asserter Methods
|
|
661
|
-
|
|
662
|
-
| Method | Description |
|
|
663
|
-
|--------|-------------|
|
|
664
|
-
| `.equals(expected)` | Assert value equality |
|
|
665
|
-
| `.is(expected)` | Assert reference equality (supports matchers) |
|
|
666
|
-
| `.never(matcher)` | Assert negation (aliases: `is_not`, `does_not`) |
|
|
667
|
-
| `.matches(matcher)` | Use any matcher |
|
|
668
|
-
| `.raises_error(class = nil, message_matcher = nil)` | Assert block raises |
|
|
669
|
-
| `.raises_nothing` | Assert block doesn't raise |
|
|
670
|
-
|
|
671
|
-
### Matcher Operators
|
|
672
|
-
|
|
673
|
-
| Operator | Description |
|
|
674
|
-
|----------|-------------|
|
|
675
|
-
| `&` | AND - both matchers must succeed |
|
|
676
|
-
| `\|` | OR - at least one matcher must succeed |
|
|
677
|
-
|
|
678
|
-
### Module Methods
|
|
679
|
-
|
|
680
|
-
| Method | Description |
|
|
681
|
-
|--------|-------------|
|
|
682
|
-
| `Minicrest.register_matcher(name, &block)` | Register custom matcher |
|
|
683
|
-
|
|
684
59
|
## License
|
|
685
60
|
|
|
686
61
|
AGPL-3.0-only
|