loupe 0.1.5

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.
@@ -0,0 +1,538 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Loupe's expectations and execution flow are heavily inspired by or adapted from Minitest and rspec-expectations
4
+ # implementations. The originals licenses can be found below.
5
+ #
6
+ # Minitest
7
+ # https://github.com/seattlerb/minitest
8
+ #
9
+ # (The MIT License)
10
+ #
11
+ # Copyright © Ryan Davis, seattle.rb
12
+ #
13
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
14
+ # documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the
15
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
16
+ # permit persons to whom the Software is furnished to do so, subject to the following conditions:
17
+ #
18
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
19
+ # Software.
20
+ #
21
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
22
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
23
+ # OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ # Rspec-expectations
27
+ #
28
+ # https://github.com/rspec/rspec-expectations
29
+ #
30
+ # The MIT License (MIT)
31
+ #
32
+ # Copyright © 2012 David Chelimsky, Myron Marston Copyright © 2006 David Chelimsky, The RSpec Development Team
33
+ # Copyright © 2005 Steven Baker
34
+ #
35
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
36
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
37
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
38
+ # permit persons to whom the Software is furnished to do so, subject to the following conditions:
39
+ #
40
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
41
+ # Software.
42
+ #
43
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
44
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
45
+ # OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
46
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
47
+
48
+ module Loupe
49
+ # Expectation
50
+ #
51
+ # This class is responsible for instantiating a target
52
+ # so that expectations can be invoked on it.
53
+ #
54
+ # Example:
55
+ # expectation = Expectation.new(target, test)
56
+ # expectation.to_be_empty
57
+ #
58
+ # The goal of ths class is so that expectations can be written
59
+ # in such a way that they read in plain English.
60
+ # E.g.: expect(something).to_be_truthy
61
+ #
62
+ # @see Loupe::Test#expect
63
+ class Expectation # rubocop:disable Metrics/ClassLength
64
+ class ExpectationFailed < StandardError; end
65
+
66
+ # @param target [BasicObject]
67
+ # @param test [Loupe::Test]
68
+ # @return [Loupe::Expectation]
69
+ def initialize(target, test)
70
+ @target = target
71
+ @color = test.color
72
+ @test = test
73
+ end
74
+
75
+ # expect(target).to_be_truthy
76
+ #
77
+ # Expects `target` to be a truthy value (not `nil` or `false`).
78
+ #
79
+ # @return [Loupe::Expectation]
80
+ def to_be_truthy
81
+ assert(@target, "Expected #{@color.p(@target.inspect, :red)} to be #{@color.p('truthy', :green)}.")
82
+ end
83
+
84
+ # expect(target).to_be_falsey
85
+ #
86
+ # Expects `target` to be a falsey value (`nil` or `false`).
87
+ #
88
+ # @return [Loupe::Expectation]
89
+ def to_be_falsey
90
+ assert(!@target, "Expected #{@color.p(@target.inspect, :red)} to be #{@color.p('falsey', :green)}.")
91
+ end
92
+
93
+ # expect(target).to_be_equal_to(value)
94
+ #
95
+ # Expects `target` to be equal to `value`. Compares if the objects are equal in terms of values
96
+ # but not if the objects are the exact same instance. For comparing identity, use {#to_be_the_same_as}.
97
+ #
98
+ # @param value [#==]
99
+ # @return [Loupe::Expectation]
100
+ def to_be_equal_to(value)
101
+ assert(
102
+ @target == value,
103
+ "Expected #{@color.p(@target.inspect, :red)} to be equal to #{@color.p(value.inspect, :green)}."
104
+ )
105
+ end
106
+
107
+ # expect(target).to_not_be_equal_to(value)
108
+ #
109
+ # Expects `target` to not be equal to `value`. Compares if the objects are different in terms of values,
110
+ # but not if the objects are the different instances. For comparing identity, use {#to_not_be_the_same_as}.
111
+ #
112
+ # @param value [#!=]
113
+ # @return [Loupe::Expectation]
114
+ def to_not_be_equal_to(value)
115
+ assert(
116
+ @target != value,
117
+ "Expected #{@color.p(@target.inspect, :red)} to not be equal to #{@color.p(value.inspect, :green)}."
118
+ )
119
+ end
120
+
121
+ # expect(target).to_be_empty
122
+ #
123
+ # Expects `target` to be empty. Which means invoking `empty?` must return `true`.
124
+ #
125
+ # @return [Loupe::Expectation]
126
+ def to_be_empty
127
+ assert(@target.empty?, "Expected #{@color.p(@target.inspect, :red)} to be empty.")
128
+ end
129
+
130
+ # expect(target).to_not_be_empty
131
+ #
132
+ # Expects `target` to not be empty. Which means invoking `empty?` must return `false`.
133
+ #
134
+ # @return [Loupe::Expectation]
135
+ def to_not_be_empty
136
+ assert(!@target.empty?, "Expected #{@color.p(@target.inspect, :red)} to not be empty.")
137
+ end
138
+
139
+ # expect(target).to_respond_to(method)
140
+ #
141
+ # Expects `target` to respond to `method`. This expectation passes if `method` exists in `target`.
142
+ #
143
+ # @param method [String, Symbol]
144
+ # @return [Loupe::Expectation]
145
+ def to_respond_to(method)
146
+ assert(
147
+ @target.respond_to?(method.to_sym),
148
+ "Expected #{@color.p(@target.inspect, :red)} to respond to #{@color.p(method, :green)}."
149
+ )
150
+ end
151
+
152
+ # expect(target).to_not_respond_to(method)
153
+ #
154
+ # Expects `target` to not respond to `method`. This expectation passes if `method` does not exist in `target`.
155
+ #
156
+ # @param method [String, Symbol]
157
+ # @return [Loupe::Expectation]
158
+ def to_not_respond_to(method)
159
+ assert(
160
+ !@target.respond_to?(method.to_sym),
161
+ "Expected #{@color.p(@target.inspect, :red)} to not respond to #{@color.p(method, :green)}."
162
+ )
163
+ end
164
+
165
+ # expect(target).to_include(object)
166
+ #
167
+ # Expects `target` to include `object`. In this expectation, `target` is typically a collection
168
+ # or another object that responds to `include?`. The expectation passes if `target` includes `object`.
169
+ #
170
+ # @param object [BasicObject]
171
+ # @return [Loupe::Expectation]
172
+ def to_include(object)
173
+ assert(
174
+ @target.include?(object),
175
+ "Expected #{@color.p(@target.inspect, :red)} to include #{@color.p(object, :green)}."
176
+ )
177
+ end
178
+
179
+ # expect(target).to_not_include(object)
180
+ #
181
+ # Expects `target` to not include `object`. In this expectation, `target` is typically a collection
182
+ # or another object that responds to `include?`. The expectation passes if `target` does not include `object`.
183
+ #
184
+ # @param object [BasicObject]
185
+ # @return [Loupe::Expectation]
186
+ def to_not_include(object)
187
+ assert(
188
+ !@target.include?(object),
189
+ "Expected #{@color.p(@target.inspect, :red)} to not include #{@color.p(object, :green)}."
190
+ )
191
+ end
192
+
193
+ # expect(target).to_be_nil
194
+ #
195
+ # Expects `target` to be `nil`.
196
+ #
197
+ # @return [Loupe::Expectation]
198
+ def to_be_nil
199
+ assert(@target.nil?, "Expected #{@color.p(@target.inspect, :red)} to be nil.")
200
+ end
201
+
202
+ # expect(target).to_not_be_nil
203
+ #
204
+ # Expects `target` not to be `nil`.
205
+ #
206
+ # @return [Loupe::Expectation]
207
+ def to_not_be_nil
208
+ assert(!@target.nil?, "Expected #{@color.p(@target.inspect, :red)} to not be nil.")
209
+ end
210
+
211
+ # expect(target).to_be_an_instance_of(klass)
212
+ #
213
+ # Expects `target` to be an instance of `klass`. For example, "ruby is awesome" is
214
+ # an instance of `String` and will pass the expectation.
215
+ #
216
+ # @param klass [Class]
217
+ # @return [Loupe::Expectation]
218
+ def to_be_an_instance_of(klass)
219
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} to be an instance " \
220
+ "of #{@color.p(klass, :green)}, not #{@color.p(@target.inspect.class, :red)}."
221
+
222
+ assert(@target.instance_of?(klass), failure_message)
223
+ end
224
+
225
+ # expect(target).to_not_be_an_instance_of(klass)
226
+ #
227
+ # Expects `target` to not be an instance of `klass`. For example, "ruby is awesome" is
228
+ # not an instance of `Integer` and will not pass the expectation.
229
+ #
230
+ # @param klass [Class]
231
+ # @return [Loupe::Expectation]
232
+ def to_not_be_an_instance_of(klass)
233
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} to not be an instance of " \
234
+ "#{@color.p(klass, :green)}, not #{@color.p(@target.inspect.class, :red)}."
235
+
236
+ assert(!@target.instance_of?(klass), failure_message)
237
+ end
238
+
239
+ # expect(target).to_be_a_kind_of(klass)
240
+ #
241
+ # Expects `target` to be a kind of `klass`. Which means that if `target.is_a?(klass)` returns true,
242
+ # the expectation will pass.
243
+ #
244
+ # @param klass [Class]
245
+ # @return [Loupe::Expectation]
246
+ def to_be_a_kind_of(klass)
247
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} to be a kind of " \
248
+ "#{@color.p(klass, :green)}, not #{@color.p(@target.inspect.class, :red)}."
249
+
250
+ assert(@target.is_a?(klass), failure_message)
251
+ end
252
+
253
+ # expect(target).to_not_be_a_kind_of(klass)
254
+ #
255
+ # Expects `target` to not be a kind of `klass`. Which means that if `target.is_a?(klass)` returns false,
256
+ # the expectation will pass.
257
+ #
258
+ # @param klass [Class]
259
+ # @return [Loupe::Expectation]
260
+ def to_not_be_a_kind_of(klass)
261
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} to not be a kind of " \
262
+ "#{@color.p(klass, :green)}, not #{@color.p(@target.inspect.class, :red)}."
263
+
264
+ assert(!@target.is_a?(klass), failure_message)
265
+ end
266
+
267
+ # expect(target).to_be(predicate)
268
+ #
269
+ # Expects `target` to return `true` for a given `predicate`. In this expectation, `predicate` is a method name and
270
+ # the expectation will pass if invoking the method on `target` returns `true`.
271
+ #
272
+ # Example:
273
+ # Verify if the result of a calculation is an odd number. The `target` is the calculation result
274
+ # and the `predicate` is the method `odd?`.
275
+ #
276
+ # calculation_result = a_complex_math_operation
277
+ # expect(calculation_result).to_be(:odd?)
278
+ #
279
+ # @param predicate [String, Symbol]
280
+ # @return [Loupe::Expectation]
281
+ def to_be(predicate)
282
+ assert(
283
+ @target.public_send(predicate),
284
+ "Expected #{@color.p(@target.inspect, :red)} to be #{@color.p(predicate, :green)}."
285
+ )
286
+ end
287
+
288
+ # expect(target).to_not_be(predicate)
289
+ #
290
+ # Expects `target` to return `false` for a given `predicate`. In this expectation, `predicate` is a method name and
291
+ # the expectation will pass if invoking the method on `target` returns `false`.
292
+ #
293
+ # Example:
294
+ # Verify if the result of a calculation is not zero. The `target` is the calculation result
295
+ # and the `predicate` is the method `zero?`.
296
+ #
297
+ # calculation_result = a_complex_math_operation
298
+ # expect(calculation_result).to_not_be(:zero?)
299
+ #
300
+ # @param predicate [String, Symbol]
301
+ # @return [Loupe::Expectation]
302
+ def to_not_be(predicate)
303
+ assert(
304
+ !@target.public_send(predicate),
305
+ "Expected #{@color.p(@target.inspect, :red)} to not be #{@color.p(predicate, :green)}."
306
+ )
307
+ end
308
+
309
+ # expect(target).to_match(object)
310
+ #
311
+ # Expects `target` to match `object`. In this expectation, `target` is a matcher (string or a regex)
312
+ # that must match `object`. The matcher needs to respond to `=~` and needs to return `true` when it is
313
+ # invoked with `object`.
314
+ #
315
+ # Example:
316
+ # expect(/ruby .*/).to_match("ruby is awesome")
317
+ # expect("awesome").to_match("ruby is awesome")
318
+ #
319
+ # @param object [BasicObject]
320
+ # @return [Loupe::Expectation]
321
+ def to_match(object)
322
+ to_respond_to(:=~)
323
+
324
+ @target = Regexp.new(Regexp.escape(@target)) if @target.is_a?(String)
325
+ assert(@target =~ object, "Expected #{@color.p(@target.inspect, :red)} to match #{@color.p(object, :green)}.")
326
+ end
327
+
328
+ # expect(target).to_not_match(object)
329
+ #
330
+ # Expects `target` to not match `object`. In this expectation, `target` is a matcher (string or a regex)
331
+ # that must not match `object`. The matcher needs to respond to `=~` and needs to return `false` when it is
332
+ # invoked with `object`.
333
+ #
334
+ # Example:
335
+ # expect(/python .*/).to_not_match("ruby is awesome")
336
+ # expect("terrible").to_not_match("ruby is awesome")
337
+ #
338
+ # @param object [BasicObject]
339
+ # @return [Loupe::Expectation]
340
+ def to_not_match(object)
341
+ to_respond_to(:=~)
342
+
343
+ @target = Regexp.new(Regexp.escape(@target)) if @target.is_a?(String)
344
+ assert(@target !~ object, "Expected #{@color.p(@target.inspect, :red)} to not match #{@color.p(object, :green)}.")
345
+ end
346
+
347
+ # expect(target).to_be_the_same_as(object)
348
+ #
349
+ # Expects `target` to be the same as `object`. This means, `target` and `object` must be the exact same
350
+ # object, with the same `object_id`.
351
+ #
352
+ # @param object [BasicObject]
353
+ # @return [Loupe::Expectation]
354
+ def to_be_the_same_as(object)
355
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} (#{@color.p(@target.inspect.object_id, :red)}) " \
356
+ "to be the same as #{@color.p(object, :green)} (#{@color.p(object.object_id, :green)})."
357
+
358
+ assert(@target.equal?(object), failure_message)
359
+ end
360
+
361
+ # expect(target).to_not_be_the_same_as(object)
362
+ #
363
+ # Expects `target` to not be the same as `object`. This means, `target` and `object` are not the exact
364
+ # same object with the same `object_id`.
365
+ #
366
+ # Note: this is an identity comparison. If the values of both objects are the same, but the object IDs are
367
+ # different, this expectation will pass.
368
+ #
369
+ # @param object [BasicObject]
370
+ # @return [Loupe::Expectation]
371
+ def to_not_be_the_same_as(object)
372
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} (#{@color.p(@target.inspect.object_id, :red)}) " \
373
+ "to not be the same as #{@color.p(object, :green)} (#{@color.p(object.object_id, :green)})."
374
+
375
+ assert(!@target.equal?(object), failure_message)
376
+ end
377
+
378
+ # expect(target).to_be_an_existing_path
379
+ #
380
+ # Expects `target` to be an existing path in the file system. That means, invoking `File.exist?(target)`
381
+ # must return `true` for this expectation to pass.
382
+ #
383
+ # @return [Loupe::Expectation]
384
+ def to_be_an_existing_path
385
+ assert(File.exist?(@target), "Expected path '#{@color.p(@target.inspect, :red)}' to exist.")
386
+ end
387
+
388
+ # expect(target).to_not_be_an_existing_path
389
+ #
390
+ # Expects `target` to not be an existing path in the file system. That means, invoking `File.exist?(target)`
391
+ # must return `false` for this expectation to pass.
392
+ #
393
+ # @return [Loupe::Expectation]
394
+ def to_not_be_an_existing_path
395
+ assert(!File.exist?(@target), "Expected path '#{@color.p(@target.inspect, :red)}' to not exist.")
396
+ end
397
+
398
+ # expect(target).to_be_in_delta_of(value, delta = 0.001)
399
+ #
400
+ # Expects `target` to be within `delta` of `value`. This means that the absolute difference between
401
+ # `target` and `value` cannot be bigger than `delta`.
402
+ #
403
+ # Example:
404
+ # expect(5.0).to_be_in_delta_of(5.1, 0.2)
405
+ #
406
+ # @param value [Numeric]
407
+ # @param delta [Numeric]
408
+ # @return [Loupe::Expectation]
409
+ def to_be_in_delta_of(value, delta = 0.001)
410
+ difference = (@target - value).abs
411
+
412
+ failure_message = "Expected |#{@target} - #{value}| " \
413
+ "(#{@color.p(difference, :red)}) to be <= #{@color.p(delta, :green)}."
414
+
415
+ assert(delta >= difference, failure_message)
416
+ end
417
+
418
+ # expect(target).to_not_be_in_delta_of(value, delta = 0.001)
419
+ #
420
+ # Expects `target` to not be within `delta` of `value`. This means that the absolute difference between
421
+ # `target` and `value` must be bigger than `delta`.
422
+ #
423
+ # Example:
424
+ # expect(5.0).to_not_be_in_delta_of(5.1, 0.01)
425
+ #
426
+ # @param value [Numeric]
427
+ # @param delta [Numeric]
428
+ # @return [Loupe::Expectation]
429
+ def to_not_be_in_delta_of(value, delta = 0.001)
430
+ difference = (@target - value).abs
431
+
432
+ failure_message = "Expected |#{@target} - #{value}| " \
433
+ "(#{@color.p(difference, :red)}) to not be <= #{@color.p(delta, :green)}."
434
+
435
+ assert(delta <= difference, failure_message)
436
+ end
437
+
438
+ # expect(target).to_be_in_epsilon_of(value, epsilon = 0.001)
439
+ #
440
+ # Expects `target` to be within `epsilon` times the smallest absolute value between `value` and `target`.
441
+ # This expectation simply invokes {#to_be_in_delta_of},
442
+ # where the `delta` is `epsilon * [@target.abs, value.abs].min`.
443
+ #
444
+ # Example:
445
+ # The minimum absolute value between 5.0 and 5.1 is equal to 5.0.
446
+ # The delta is equal to 5.0 * 0.1, which is 0.5.
447
+ # The absolute difference 5.1 - 5.0 is 0.1.
448
+ # 0.1 is smaller than 0.5, therefore the expectation passes.
449
+ #
450
+ # expect(5.0).to_be_in_epsilon_of(5.1, 0.1)
451
+ #
452
+ # @param value [Numeric]
453
+ # @param epsilon [Numeric]
454
+ # @return [Loupe::Expectation]
455
+ def to_be_in_epsilon_of(value, epsilon = 0.001)
456
+ to_be_in_delta_of(value, [@target.abs, value.abs].min * epsilon)
457
+ end
458
+
459
+ # expect(target).to_not_be_in_epsilon_of(value, epsilon = 0.001)
460
+ #
461
+ # Expects `target` to not be within `epsilon` times the smallest absolute value between `value` and `target`.
462
+ # This expectation simply invokes {#to_not_be_in_delta_of},
463
+ # where the `delta` is `epsilon * [@target.abs, value.abs].min`.
464
+ #
465
+ # Example:
466
+ # The minimum absolute value between 5.0 and 5.1 is equal to 5.0.
467
+ # The delta is equal to 5.0 * 0.01, which is 0.05.
468
+ # The absolute difference 5.1 - 5.0 is 0.1.
469
+ # 0.1 is not smaller than 0.05, therefore the expectation passes.
470
+ #
471
+ # expect(5.0).to_not_be_in_epsilon_of(5.1, 0.01)
472
+ #
473
+ # @param value [Numeric]
474
+ # @param epsilon [Numeric]
475
+ # @return [Loupe::Expectation]
476
+ def to_not_be_in_epsilon_of(value, epsilon = 0.001)
477
+ to_not_be_in_delta_of(value, [@target.abs, value.abs].min * epsilon)
478
+ end
479
+
480
+ # expect(target).to_satisfy_operator(operator, other)
481
+ #
482
+ # Expects `target` to return true when the `operator` is applied on `other`.
483
+ # This expectation is used to verify operations between two objects.
484
+ #
485
+ # Example:
486
+ #
487
+ # expect(5.0).to_satisfy_operator(:>, 4.9)
488
+ #
489
+ # @param operator [Symbol]
490
+ # @param other [BasicObject]
491
+ # @return [Loupe::Expectation]
492
+ def to_satisfy_operator(operator, other)
493
+ return to_be(operator) unless other
494
+
495
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} to be #{operator}" \
496
+ " #{@color.p(other, :green)}."
497
+
498
+ assert(@target.public_send(operator, other), failure_message)
499
+ end
500
+
501
+ # expect(target).to_not_satisfy_operator(operator, other)
502
+ #
503
+ # Expects `target` to return false when the `operator` is applied on `other`.
504
+ # This expectation is used to verify operations between two objects.
505
+ #
506
+ # Example:
507
+ #
508
+ # expect(5.0).to_not_satisfy_operator(:<, 4.9)
509
+ #
510
+ # @param operator [Symbol]
511
+ # @param other [BasicObject]
512
+ # @return [Loupe::Expectation]
513
+ def to_not_satisfy_operator(operator, other)
514
+ return to_not_be(operator) unless other
515
+
516
+ failure_message = "Expected #{@color.p(@target.inspect, :red)} to not be #{operator}" \
517
+ " #{@color.p(other, :green)}."
518
+
519
+ assert(!@target.public_send(operator, other), failure_message)
520
+ end
521
+
522
+ private
523
+
524
+ # Base assertion for all expectations. This is where result are passed to the reported
525
+ # and where the test execution is halted if any expectation fails.
526
+ #
527
+ # @param value [BasicObject]
528
+ # @param failure_message [String]
529
+ # @return [Loupe::Expectation]
530
+ def assert(value, failure_message)
531
+ @test.reporter.increment_expectation_count
532
+ return self if value
533
+
534
+ @test.reporter.increment_failure_count(@test, failure_message)
535
+ raise ExpectationFailed
536
+ end
537
+ end
538
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Loupe
4
+ # Failure
5
+ #
6
+ # This class represents a single test failure. It corresponds
7
+ # to one method that was executed and had failed expectations.
8
+ class Failure
9
+ # @return [String]
10
+ attr_reader :file_name
11
+
12
+ # @return [String]
13
+ attr_reader :test_name
14
+
15
+ # @return [String]
16
+ attr_reader :message
17
+
18
+ # @return [Integer]
19
+ attr_reader :line_number
20
+
21
+ # @return [Class]
22
+ attr_reader :klass
23
+
24
+ # @param test [Loupe::Test]
25
+ # @param message [String]
26
+ # @return [Loupe::Failure]
27
+ def initialize(test, message)
28
+ @file_name = test.file
29
+ @test_name = test.name
30
+ @line_number = test.line_number
31
+ @klass = test.class
32
+ @color = test.color
33
+ @message = message
34
+ end
35
+
36
+ # @return [String]
37
+ def to_s
38
+ "#{file_name}:#{line_number} at #{@color.p(test_name, :yellow)}. #{message}"
39
+ end
40
+
41
+ # @return [Array<String>]
42
+ def location_and_message
43
+ [
44
+ "#{file_name}:#{line_number} at #{@color.p(test_name, :yellow)}",
45
+ message
46
+ ]
47
+ end
48
+ end
49
+ end