r_spec-clone 1.4.0 → 1.7.0
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/LICENSE.md +2 -2
- data/README.md +33 -34
- data/lib/r_spec/clone/dsl.rb +17 -216
- data/lib/r_spec/clone/expectation_helper/it.rb +1 -1
- data/lib/r_spec/clone/expectation_helper/shared.rb +33 -1
- data/lib/r_spec/clone/expectation_target/base.rb +7 -3
- data/lib/r_spec/clone/{console.rb → logger.rb} +8 -4
- data/lib/r_spec.rb +0 -87
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6014d4cd0ffe271d71ff599cdba7ce291b5329c062aeea611c292dcb9d24d822
|
4
|
+
data.tar.gz: 96e14ce3c34c9d5d6e9a6c49769c94db2562e2a14eaeae94e6415884f2f5c7eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7bd806d2a1a220c86320a6a8fa93bf9b19f60ac2a0b4f03f510f727d6d0132995c0dde783659923c2031d7f0864b63f5137976c136d3c1c90a62ecd8996ef25
|
7
|
+
data.tar.gz: 4eda5fc59e05cb4a2a20e18cc403a89985552737b551d2f343fedf3b9f98f6dd572ef977c0164926b5b0703a9b91b2901189bcad6823618558c908df6a869c4a
|
data/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
The MIT License
|
1
|
+
# The MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2015-
|
3
|
+
Copyright (c) 2015-2022 Cyril Kato
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -15,14 +15,14 @@ A minimalist __RSpec clone__ with all the essentials.
|
|
15
15
|
|
16
16
|
## Project goals
|
17
17
|
|
18
|
-
1. Keep
|
19
|
-
2.
|
18
|
+
1. Keep code complexity low, avoid false negatives and false positives.
|
19
|
+
2. Load specifications in simple, atomic and thread safe Ruby primitives.
|
20
20
|
3. Avoid overloading the interface with additional alternative syntaxes.
|
21
|
-
4. Provide
|
21
|
+
4. Provide the basics of DSL RSpec to write tests.
|
22
22
|
|
23
23
|
## Some differences
|
24
24
|
|
25
|
-
* There is no option to
|
25
|
+
* There is no option to enable monkey-patching.
|
26
26
|
* It does not rely on [hacks such as `at_exit` hook](https://blog.arkency.com/2013/06/are-we-abusing-at-exit/) to trigger the tests.
|
27
27
|
* Malicious _actual values_ cannot [hack results](https://asciinema.org/a/423547?autoplay=1&speed=2).
|
28
28
|
* If no `subject` has been explicitly determined, none is defined.
|
@@ -31,8 +31,9 @@ A minimalist __RSpec clone__ with all the essentials.
|
|
31
31
|
* [Arbitrary helper methods](https://relishapp.com/rspec/rspec-core/v/3-10/docs/helper-methods/arbitrary-helper-methods) are not exposed to examples.
|
32
32
|
* The `let` method defines a helper method rather than a memoized helper method.
|
33
33
|
* The one-liner `is_expected` syntax also works with block expectations.
|
34
|
-
* `subject`, `before
|
35
|
-
*
|
34
|
+
* `subject`, `before` and `let` definitions must come before examples.
|
35
|
+
* The execution of the test suite stops as soon as an error is detected.
|
36
|
+
* Each `context` block isolates its tests and possible side effects.
|
36
37
|
|
37
38
|
## Installation
|
38
39
|
|
@@ -72,9 +73,10 @@ To use the `RSpec` module and its DSL, you need to add `require "r_spec"` to you
|
|
72
73
|
Many projects use a custom spec helper which organizes these includes.
|
73
74
|
|
74
75
|
Concrete test cases are defined in `it` blocks.
|
75
|
-
An optional descriptive string
|
76
|
+
An optional (but recommended) descriptive string or module indicates the purpose of the test and a block contains the main logic of the test.
|
76
77
|
|
77
|
-
Test cases that have been defined or outlined but are not yet expected to work can be defined using `pending` instead of `it`.
|
78
|
+
Test cases that have been defined or outlined but are not yet expected to work can be defined using `pending` instead of `it`.
|
79
|
+
They will not be run but show up in the spec report as pending.
|
78
80
|
|
79
81
|
An `it` block contains an example that should invoke the code to be tested and define what is expected of it.
|
80
82
|
Each example can contain multiple expectations, but it should test only one specific behaviour.
|
@@ -85,7 +87,7 @@ To express an expectation, wrap an object or block in `expect`, call `to` (or `n
|
|
85
87
|
If the expectation is met, code execution continues.
|
86
88
|
Otherwise the example has _failed_ and other code will not be executed.
|
87
89
|
|
88
|
-
In test files, specs
|
90
|
+
In test files, specs can be structured by example groups which are defined by `describe` and `context` sections.
|
89
91
|
Typically a top level `describe` defines the outer unit (such as a class) to be tested by the spec.
|
90
92
|
Further `describe` sections can be nested within the outer unit to specify smaller units under test (such as individual methods).
|
91
93
|
|
@@ -96,28 +98,10 @@ For unit tests, it is recommended to follow the conventions for method names:
|
|
96
98
|
|
97
99
|
To establish certain contexts — think _empty array_ versus _array with elements_ — the `context` method may be used to communicate this to the reader.
|
98
100
|
|
99
|
-
|
101
|
+
Unlike a `describe` block, all specifications executed within a `context` are isolated in a subprocess.
|
102
|
+
This prevents possible side effects on the Ruby object environment from being propagated outside their context, which could alter the result of the unit test suite.
|
100
103
|
|
101
|
-
|
102
|
-
app = "foo"
|
103
|
-
|
104
|
-
RSpec.describe "Side effects per example" do
|
105
|
-
it! "runs the example in isolation" do
|
106
|
-
expect { app.gsub!("foo", "bar") }.to eq "bar"
|
107
|
-
expect(app).to eq "bar"
|
108
|
-
end
|
109
|
-
|
110
|
-
it "runs the example" do
|
111
|
-
expect(app).to eq "foo"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
# Success: expected to eq "bar".
|
116
|
-
# Success: expected to eq "bar".
|
117
|
-
# Success: expected to eq "foo".
|
118
|
-
```
|
119
|
-
|
120
|
-
Note: if you are wondering what the Ruby code generated by using the DSL might look like, an article presents the correspondence between each method via simple examples, available in [English](https://dev.to/cyri_/what-ruby-code-to-expect-from-a-testing-dsl-4oe1), [Chinese](https://ruby-china.org/topics/41441) and [Japanese](https://qiita.com/cyril/items/17ee758e162bae144a07).
|
104
|
+
Note: if you are wondering what kind of code might be generated by the DSL, an article that shows the dynamic transcription of the main methods with simple examples is available in [Chinese](https://ruby-china.org/topics/41441), in [English](https://dev.to/cyri_/what-ruby-code-to-expect-from-a-testing-dsl-4oe1) and in [Japanese](https://qiita.com/cyril/items/17ee758e162bae144a07).
|
121
105
|
|
122
106
|
### Expectations
|
123
107
|
|
@@ -180,9 +164,24 @@ expect(actual).to be_instance_of(expected) # passes if expected.equal?(actual
|
|
180
164
|
expect(actual).to be_an_instance_of(expected) # passes if expected.equal?(actual.class)
|
181
165
|
```
|
182
166
|
|
167
|
+
#### Predicate
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
expect(actual).to be_xxx # passes if actual.xxx?
|
171
|
+
expect(actual).to be_have_xxx(:yyy) # passes if actual.has_xxx?(:yyy)
|
172
|
+
```
|
173
|
+
|
174
|
+
##### Examples
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
expect([]).to be_empty
|
178
|
+
expect(foo: 1).to have_key(:foo)
|
179
|
+
```
|
180
|
+
|
183
181
|
#### Change
|
184
182
|
|
185
183
|
```ruby
|
184
|
+
expect { object.action }.to change(object, :value).to(new)
|
186
185
|
expect { object.action }.to change(object, :value).from(old).to(new)
|
187
186
|
expect { object.action }.to change(object, :value).by(delta)
|
188
187
|
expect { object.action }.to change(object, :value).by_at_least(minimum_delta)
|
@@ -269,7 +268,7 @@ Benchmark against [100 executions of a file containing 1 expectation](https://gi
|
|
269
268
|
|
270
269
|
### Runtime
|
271
270
|
|
272
|
-
Benchmark against [1 execution of a file containing
|
271
|
+
Benchmark against [1 execution of a file containing 100,000 expectations](https://github.com/cyril/r_spec-clone.rb/blob/main/benchmark/run_time/) (lower is better).
|
273
272
|
|
274
273
|

|
275
274
|
|
@@ -281,7 +280,7 @@ __RSpec clone__'s specifications are self-described here: [spec/](https://github
|
|
281
280
|
|
282
281
|
* Home page: [https://r-spec.dev/](https://r-spec.dev/)
|
283
282
|
* Cheatsheet: [https://r-spec.dev/cheatsheet.html](https://r-spec.dev/cheatsheet.html)
|
284
|
-
* Blog post: [https://
|
283
|
+
* Blog post: [https://cyrilllllll.medium.com/introducing-a-new-rspec-850d48c0f901](https://cyrilllllll.medium.com/introducing-a-new-rspec-850d48c0f901)
|
285
284
|
* Source code: [https://github.com/cyril/r_spec-clone.rb](https://github.com/cyril/r_spec-clone.rb)
|
286
285
|
* API Doc: [https://rubydoc.info/gems/r_spec-clone](https://rubydoc.info/gems/r_spec-clone)
|
287
286
|
* Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
|
@@ -295,9 +294,9 @@ Without RSpec, this clone would not have been possible.
|
|
295
294
|
|
296
295
|
## Buy me a coffee ☕
|
297
296
|
|
298
|
-
If you like this project, please consider making a small donation
|
297
|
+
If you like this project, please consider making a small donation.
|
299
298
|
|
300
|
-
[](https://etherscan.io/address/cyr.eth)
|
301
300
|
|
302
301
|
## Versioning
|
303
302
|
|
data/lib/r_spec/clone/dsl.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
3
|
+
require_relative "logger"
|
4
4
|
require_relative "error"
|
5
5
|
require_relative "expectation_helper"
|
6
6
|
|
@@ -9,9 +9,8 @@ module RSpec
|
|
9
9
|
# Abstract class for handling the domain-specific language.
|
10
10
|
class Dsl
|
11
11
|
BEFORE_METHOD = :initialize
|
12
|
-
AFTER_METHOD = :terminate
|
13
12
|
|
14
|
-
private_constant :BEFORE_METHOD
|
13
|
+
private_constant :BEFORE_METHOD
|
15
14
|
|
16
15
|
# Executes the given block before each spec in the current context runs.
|
17
16
|
#
|
@@ -53,35 +52,6 @@ module RSpec
|
|
53
52
|
private BEFORE_METHOD
|
54
53
|
end
|
55
54
|
|
56
|
-
# Executes the given block after each spec in the current context runs.
|
57
|
-
#
|
58
|
-
# @example
|
59
|
-
# require "r_spec"
|
60
|
-
#
|
61
|
-
# RSpec.describe Integer do
|
62
|
-
# after do
|
63
|
-
# puts "That is the answer to everything."
|
64
|
-
# end
|
65
|
-
#
|
66
|
-
# it { expect(42).to be 42 }
|
67
|
-
# end
|
68
|
-
#
|
69
|
-
# # Output to the console
|
70
|
-
# # Success: expected to be 42.
|
71
|
-
# # That is the answer to everything.
|
72
|
-
#
|
73
|
-
# @param block [Proc] The content to execute at the class initialization.
|
74
|
-
#
|
75
|
-
# @api public
|
76
|
-
def self.after(&block)
|
77
|
-
define_method(AFTER_METHOD) do
|
78
|
-
instance_exec(&block)
|
79
|
-
super()
|
80
|
-
end
|
81
|
-
|
82
|
-
private AFTER_METHOD
|
83
|
-
end
|
84
|
-
|
85
55
|
# Sets a user-defined property.
|
86
56
|
#
|
87
57
|
# @example
|
@@ -110,7 +80,7 @@ module RSpec
|
|
110
80
|
#
|
111
81
|
# @api public
|
112
82
|
def self.let(name, *args, **kwargs, &block)
|
113
|
-
raise Error::ReservedMethod if
|
83
|
+
raise Error::ReservedMethod if BEFORE_METHOD.equal?(name.to_sym)
|
114
84
|
|
115
85
|
private define_method(name, *args, **kwargs, &block)
|
116
86
|
end
|
@@ -173,50 +143,14 @@ module RSpec
|
|
173
143
|
|
174
144
|
# :nocov:
|
175
145
|
|
176
|
-
# Runs a describe example group in a subprocess to isolate side effects.
|
177
|
-
#
|
178
|
-
# @example
|
179
|
-
# $app = "foo"
|
180
|
-
#
|
181
|
-
# require "r_spec"
|
182
|
-
#
|
183
|
-
# RSpec.describe "Scoped side effects" do
|
184
|
-
# describe! "#gsub!" do
|
185
|
-
# before do
|
186
|
-
# $app.gsub!("o", "0")
|
187
|
-
# end
|
188
|
-
#
|
189
|
-
# context! "when isolated in the context" do
|
190
|
-
# before do
|
191
|
-
# $app.gsub!("f", "F")
|
192
|
-
# end
|
193
|
-
#
|
194
|
-
# it { expect($app).to eq "F00" }
|
195
|
-
# end
|
196
|
-
#
|
197
|
-
# it { expect($app).to eq "f00" }
|
198
|
-
# end
|
199
|
-
#
|
200
|
-
# it { expect($app).to eq "foo" }
|
201
|
-
# end
|
202
|
-
#
|
203
|
-
# # Output to the console
|
204
|
-
# # Success: expected to eq "F00".
|
205
|
-
# # Success: expected to eq "f00".
|
206
|
-
# # Success: expected to eq "foo".
|
207
|
-
#
|
208
|
-
# @param (see #describe)
|
209
|
-
#
|
210
|
-
# @api public
|
211
|
-
def self.describe!(const, &block)
|
212
|
-
fork! { describe(const, &block) }
|
213
|
-
end
|
214
|
-
|
215
|
-
# :nocov:
|
216
|
-
|
217
146
|
# Defines an example group that establishes a specific context, like
|
218
147
|
# _empty array_ versus _array with elements_.
|
219
148
|
#
|
149
|
+
# Unlike a `describe` block, all specifications executed within a
|
150
|
+
# `context` are isolated in a subprocess. This prevents possible side
|
151
|
+
# effects on the Ruby object environment from being propagated outside
|
152
|
+
# their context, which could alter the result of the unit test suite.
|
153
|
+
#
|
220
154
|
# @example
|
221
155
|
# require "r_spec"
|
222
156
|
#
|
@@ -240,50 +174,8 @@ module RSpec
|
|
240
174
|
#
|
241
175
|
# @api public
|
242
176
|
def self.context(_description, &block)
|
243
|
-
|
244
|
-
|
245
|
-
end
|
246
|
-
|
247
|
-
# :nocov:
|
248
|
-
|
249
|
-
# Runs a context example group in a subprocess to isolate side effects.
|
250
|
-
#
|
251
|
-
# @example
|
252
|
-
# app = "Hello, world!"
|
253
|
-
#
|
254
|
-
# require "r_spec"
|
255
|
-
#
|
256
|
-
# RSpec.describe String do
|
257
|
-
# subject do
|
258
|
-
# app
|
259
|
-
# end
|
260
|
-
#
|
261
|
-
# before do
|
262
|
-
# subject.gsub!("world", person)
|
263
|
-
# end
|
264
|
-
#
|
265
|
-
# context! "when Alice is greeted" do
|
266
|
-
# let(:person) { "Alice" }
|
267
|
-
#
|
268
|
-
# it { is_expected.to eq "Hello, Alice!" }
|
269
|
-
# end
|
270
|
-
#
|
271
|
-
# context! "when Bob is greeted" do
|
272
|
-
# let(:person) { "Bob" }
|
273
|
-
#
|
274
|
-
# it { is_expected.to eq "Hello, Bob!" }
|
275
|
-
# end
|
276
|
-
# end
|
277
|
-
#
|
278
|
-
# # Output to the console
|
279
|
-
# # Success: expected to eq "Hello, Alice!".
|
280
|
-
# # Success: expected to eq "Hello, Bob!".
|
281
|
-
#
|
282
|
-
# @param (see #context)
|
283
|
-
#
|
284
|
-
# @api public
|
285
|
-
def self.context!(description, &block)
|
286
|
-
fork! { context(description, &block) }
|
177
|
+
pid = ::Process.fork { ::Class.new(self).instance_eval(&block) }
|
178
|
+
exit false unless ::Process::Status.wait(pid).exitstatus.zero?
|
287
179
|
end
|
288
180
|
|
289
181
|
# :nocov:
|
@@ -329,42 +221,8 @@ module RSpec
|
|
329
221
|
#
|
330
222
|
# @api public
|
331
223
|
def self.it(_name = nil, &block)
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
# :nocov:
|
336
|
-
|
337
|
-
# Runs a concrete test case in a subprocess to isolate side effects.
|
338
|
-
#
|
339
|
-
# @example
|
340
|
-
# app = "foo"
|
341
|
-
#
|
342
|
-
# require "r_spec"
|
343
|
-
#
|
344
|
-
# RSpec.describe "Side effects per example" do
|
345
|
-
# it! "runs the example in isolation" do
|
346
|
-
# expect { app.gsub!("foo", "bar") }.to eq "bar"
|
347
|
-
# expect(app).to eq "bar"
|
348
|
-
# end
|
349
|
-
#
|
350
|
-
# it "runs the example" do
|
351
|
-
# expect(app).to eq "foo"
|
352
|
-
# end
|
353
|
-
# end
|
354
|
-
#
|
355
|
-
# # Output to the console
|
356
|
-
# # Success: expected to eq "bar".
|
357
|
-
# # Success: expected to eq "bar".
|
358
|
-
# # Success: expected to eq "foo".
|
359
|
-
#
|
360
|
-
# @param (see #it)
|
361
|
-
#
|
362
|
-
# @raise (see ExpectationTarget::Base#result)
|
363
|
-
# @return (see ExpectationTarget::Base#result)
|
364
|
-
#
|
365
|
-
# @api public
|
366
|
-
def self.it!(name = nil, &block)
|
367
|
-
fork! { it(name, &block) }
|
224
|
+
Logger.source(*block.source_location)
|
225
|
+
example_without_attribute.new.instance_eval(&block)
|
368
226
|
end
|
369
227
|
|
370
228
|
# :nocov:
|
@@ -416,43 +274,9 @@ module RSpec
|
|
416
274
|
#
|
417
275
|
# @api public
|
418
276
|
def self.its(attribute, *args, **kwargs, &block)
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
# :nocov:
|
423
|
-
|
424
|
-
# Runs a single concrete test case in a subprocess to isolate side
|
425
|
-
# effects.
|
426
|
-
#
|
427
|
-
# @example
|
428
|
-
# app = "foo"
|
429
|
-
#
|
430
|
-
# require "r_spec"
|
431
|
-
#
|
432
|
-
# RSpec.describe "Isolated side effect" do
|
433
|
-
# subject do
|
434
|
-
# app
|
435
|
-
# end
|
436
|
-
#
|
437
|
-
# its!(:upcase) { is_expected.to eq "FOO" }
|
438
|
-
#
|
439
|
-
# it "tests the original value" do
|
440
|
-
# expect(app).to eq "foo"
|
441
|
-
# end
|
442
|
-
# end
|
443
|
-
#
|
444
|
-
# # Output to the console
|
445
|
-
# # Success: expected to eq "FOO".
|
446
|
-
# # Success: expected to eq "foo".
|
447
|
-
#
|
448
|
-
# @param (see #it)
|
449
|
-
#
|
450
|
-
# @raise (see ExpectationTarget::Base#result)
|
451
|
-
# @return (see ExpectationTarget::Base#result)
|
452
|
-
#
|
453
|
-
# @api public
|
454
|
-
def self.its!(attribute, *args, **kwargs, &block)
|
455
|
-
fork! { its(attribute, *args, **kwargs, &block) }
|
277
|
+
Logger.source(*block.source_location)
|
278
|
+
example_with_attribute(attribute, *args, **kwargs).new
|
279
|
+
.instance_eval(&block)
|
456
280
|
end
|
457
281
|
|
458
282
|
# :nocov:
|
@@ -483,7 +307,7 @@ module RSpec
|
|
483
307
|
#
|
484
308
|
# @api public
|
485
309
|
def self.pending(message)
|
486
|
-
|
310
|
+
Logger.passed_spec Error::PendingExpectation.result(message)
|
487
311
|
end
|
488
312
|
|
489
313
|
# Example class for concrete test case.
|
@@ -505,26 +329,7 @@ module RSpec
|
|
505
329
|
end
|
506
330
|
end
|
507
331
|
|
508
|
-
|
509
|
-
def self.fork!(&block)
|
510
|
-
pid = fork(&block)
|
511
|
-
thread = ::Process.detach(pid)
|
512
|
-
exitstatus = thread.join.value.exitstatus
|
513
|
-
exit false unless exitstatus.zero?
|
514
|
-
end
|
515
|
-
|
516
|
-
# Execution of specifications.
|
517
|
-
def self.run(example, &block)
|
518
|
-
example.instance_eval(&block)
|
519
|
-
rescue ::SystemExit
|
520
|
-
Console.source(*block.source_location)
|
521
|
-
|
522
|
-
exit false
|
523
|
-
ensure
|
524
|
-
example&.send(AFTER_METHOD)
|
525
|
-
end
|
526
|
-
|
527
|
-
private_class_method :example_without_attribute, :example_with_attribute, :fork!, :run
|
332
|
+
private_class_method :example_without_attribute, :example_with_attribute
|
528
333
|
|
529
334
|
private
|
530
335
|
|
@@ -539,10 +344,6 @@ module RSpec
|
|
539
344
|
def subject
|
540
345
|
raise Error::UndefinedSubject, "subject not explicitly defined"
|
541
346
|
end
|
542
|
-
|
543
|
-
define_method(AFTER_METHOD) do
|
544
|
-
# do nothing by default
|
545
|
-
end
|
546
347
|
end
|
547
348
|
end
|
548
349
|
end
|
@@ -19,7 +19,7 @@ module RSpec
|
|
19
19
|
#
|
20
20
|
# @example
|
21
21
|
# expect("foo") # => #<RSpec::Clone::ExpectationTarget::Value:0x00007f @actual="foo">
|
22
|
-
# expect { Boom } # => #<RSpec::Clone::ExpectationTarget::Block:
|
22
|
+
# expect { RSpec::Clone::Boom! } # => #<RSpec::Clone::ExpectationTarget::Block:0x... @callable=#<Proc:0x...>>
|
23
23
|
#
|
24
24
|
# @api public
|
25
25
|
def expect(value = self.class.superclass, &block)
|
@@ -87,7 +87,7 @@ module RSpec
|
|
87
87
|
#
|
88
88
|
# @example
|
89
89
|
# matcher = raise_exception(NameError)
|
90
|
-
# matcher.matches? { Boom } # => true
|
90
|
+
# matcher.matches? { RSpec::Clone::Boom! } # => true
|
91
91
|
# matcher.matches? { true } # => false
|
92
92
|
#
|
93
93
|
# @param expected [Exception, #to_s] The expected exception name.
|
@@ -212,6 +212,38 @@ module RSpec
|
|
212
212
|
def satisfy(&expected)
|
213
213
|
::Matchi::Satisfy.new(&expected)
|
214
214
|
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
# Predicate matcher, or default method missing behavior.
|
219
|
+
#
|
220
|
+
# @example Empty predicate matcher
|
221
|
+
# matcher = be_empty
|
222
|
+
# matcher.matches? { [] } # => true
|
223
|
+
# matcher.matches? { [4] } # => false
|
224
|
+
def method_missing(name, *args, **kwargs, &block)
|
225
|
+
return super unless predicate_matcher_name?(name)
|
226
|
+
|
227
|
+
::Matchi::Predicate.new(name, *args, **kwargs, &block)
|
228
|
+
end
|
229
|
+
|
230
|
+
# :nocov:
|
231
|
+
|
232
|
+
# Hook method to return whether the obj can respond to id method or not.
|
233
|
+
def respond_to_missing?(name, include_private = false)
|
234
|
+
predicate_matcher_name?(name) || super
|
235
|
+
end
|
236
|
+
|
237
|
+
# :nocov:
|
238
|
+
|
239
|
+
# Predicate matcher name detector.
|
240
|
+
#
|
241
|
+
# @param name [Array, Symbol] The name of a potential predicate matcher.
|
242
|
+
#
|
243
|
+
# @return [Boolean] Indicates if it is a predicate matcher name or not.
|
244
|
+
def predicate_matcher_name?(name)
|
245
|
+
name.start_with?("be_", "have_") && !name.end_with?("!", "?")
|
246
|
+
end
|
215
247
|
end
|
216
248
|
end
|
217
249
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "expresenter"
|
4
4
|
require "test_tube"
|
5
5
|
|
6
|
-
require_relative File.join("..", "
|
6
|
+
require_relative File.join("..", "logger")
|
7
7
|
|
8
8
|
module RSpec
|
9
9
|
module Clone
|
@@ -82,6 +82,8 @@ module RSpec
|
|
82
82
|
test.got.equal?(true)
|
83
83
|
end
|
84
84
|
|
85
|
+
# :nocov:
|
86
|
+
|
85
87
|
# @param passed [Boolean] The high expectation passed or failed.
|
86
88
|
# @param actual [#object_id] The actual value.
|
87
89
|
# @param error [Exception, nil] Any raised exception.
|
@@ -94,7 +96,7 @@ module RSpec
|
|
94
96
|
# @raise [SystemExit] Terminate execution immediately by calling
|
95
97
|
# `Kernel.exit(false)` with a failure message written to STDERR.
|
96
98
|
def result(passed, actual:, error:, got:, matcher:, negate:)
|
97
|
-
|
99
|
+
Logger.passed_spec ::Expresenter.call(passed).with(
|
98
100
|
actual: actual,
|
99
101
|
definition: matcher.to_s,
|
100
102
|
error: error,
|
@@ -104,8 +106,10 @@ module RSpec
|
|
104
106
|
level: :MUST
|
105
107
|
)
|
106
108
|
rescue ::Expresenter::Fail => e
|
107
|
-
|
109
|
+
Logger.failed_spec(e)
|
108
110
|
end
|
111
|
+
|
112
|
+
# :nocov:
|
109
113
|
end
|
110
114
|
end
|
111
115
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RSpec
|
4
4
|
module Clone
|
5
5
|
# Send log messages to the console.
|
6
|
-
module
|
6
|
+
module Logger
|
7
7
|
# @param report [::Expresenter::Pass] Passed expectation result presenter.
|
8
8
|
#
|
9
9
|
# @see https://github.com/fixrb/expresenter
|
@@ -13,17 +13,21 @@ module RSpec
|
|
13
13
|
puts report.colored_string
|
14
14
|
end
|
15
15
|
|
16
|
+
# :nocov:
|
17
|
+
|
16
18
|
# @param report [::Expresenter::Fail] Failed expectation result presenter.
|
17
19
|
#
|
18
20
|
# @see https://github.com/fixrb/expresenter
|
19
21
|
#
|
20
|
-
# @raise [SystemExit] Terminate execution immediately with
|
22
|
+
# @raise [SystemExit] Terminate execution immediately with message.
|
21
23
|
def self.failed_spec(report)
|
22
24
|
abort report.colored_string
|
23
25
|
end
|
24
26
|
|
25
|
-
#
|
26
|
-
|
27
|
+
# :nocov:
|
28
|
+
|
29
|
+
# The Ruby source filename and line number containing this method or nil
|
30
|
+
# if this method was not defined in Ruby (i.e. native).
|
27
31
|
#
|
28
32
|
# @param filename [String, nil] The Ruby source filename.
|
29
33
|
# @param line [Integer, nil] The Ruby source line number.
|
data/lib/r_spec.rb
CHANGED
@@ -89,36 +89,6 @@ module RSpec
|
|
89
89
|
|
90
90
|
# :nocov:
|
91
91
|
|
92
|
-
# Runs a context example group in a subprocess to isolate side effects.
|
93
|
-
#
|
94
|
-
# @example
|
95
|
-
# str = "Hello, world!"
|
96
|
-
#
|
97
|
-
# require "r_spec"
|
98
|
-
#
|
99
|
-
# RSpec.context! "when a string becomes uppercase" do
|
100
|
-
# before do
|
101
|
-
# str.upcase!
|
102
|
-
# end
|
103
|
-
#
|
104
|
-
# it { expect(str).to eq "HELLO, WORLD!" }
|
105
|
-
# end
|
106
|
-
#
|
107
|
-
# # Output to the console
|
108
|
-
# # Success: expected to eq "HELLO, WORLD!".
|
109
|
-
#
|
110
|
-
# RSpec.it { expect(str).to eq "Hello, world!" }
|
111
|
-
#
|
112
|
-
# # Output to the console
|
113
|
-
# # Success: expected to eq "Hello, world!".
|
114
|
-
#
|
115
|
-
# @param (see #context)
|
116
|
-
def self.context!(description, &block)
|
117
|
-
Clone::Dsl.context!(description, &block)
|
118
|
-
end
|
119
|
-
|
120
|
-
# :nocov:
|
121
|
-
|
122
92
|
# Defines an example group that describes a unit to be tested.
|
123
93
|
#
|
124
94
|
# @example
|
@@ -153,36 +123,6 @@ module RSpec
|
|
153
123
|
|
154
124
|
# :nocov:
|
155
125
|
|
156
|
-
# Runs a describe example group in a subprocess to isolate side effects.
|
157
|
-
#
|
158
|
-
# @example
|
159
|
-
# $app = "foo"
|
160
|
-
#
|
161
|
-
# require "r_spec"
|
162
|
-
#
|
163
|
-
# RSpec.describe! "#gsub!" do
|
164
|
-
# before do
|
165
|
-
# $app.gsub!("o", "0")
|
166
|
-
# end
|
167
|
-
#
|
168
|
-
# it { expect($app).to eq "f00" }
|
169
|
-
# end
|
170
|
-
#
|
171
|
-
# # Output to the console
|
172
|
-
# # Success: expected to eq "f00".
|
173
|
-
#
|
174
|
-
# RSpec.it { expect($app).to eq "foo" }
|
175
|
-
#
|
176
|
-
# # Output to the console
|
177
|
-
# # Success: expected to eq "foo".
|
178
|
-
#
|
179
|
-
# @param (see #describe)
|
180
|
-
def self.describe!(const, &block)
|
181
|
-
Clone::Dsl.describe!(const, &block)
|
182
|
-
end
|
183
|
-
|
184
|
-
# :nocov:
|
185
|
-
|
186
126
|
# Defines a concrete test case.
|
187
127
|
#
|
188
128
|
# The test is performed by the block supplied to &block.
|
@@ -209,33 +149,6 @@ module RSpec
|
|
209
149
|
|
210
150
|
# :nocov:
|
211
151
|
|
212
|
-
# Runs a concrete test case in a subprocess to isolate side effects.
|
213
|
-
#
|
214
|
-
# @example
|
215
|
-
# app = "Hello, world!"
|
216
|
-
#
|
217
|
-
# require "r_spec"
|
218
|
-
#
|
219
|
-
# RSpec.it! { expect(app.gsub!("world", "Alice")).to eq "Hello, Alice!" }
|
220
|
-
#
|
221
|
-
# # Output to the console
|
222
|
-
# # Success: expected to eq "Hello, Alice!".
|
223
|
-
#
|
224
|
-
# RSpec.it { expect(app).to eq "Hello, world!" }
|
225
|
-
#
|
226
|
-
# # Output to the console
|
227
|
-
# # Success: expected to eq "Hello, world!".
|
228
|
-
#
|
229
|
-
# @param (see #it)
|
230
|
-
#
|
231
|
-
# @raise (see ExpectationTarget::Base#result)
|
232
|
-
# @return (see ExpectationTarget::Base#result)
|
233
|
-
def self.it!(name = nil, &block)
|
234
|
-
Clone::Dsl.it!(name, &block)
|
235
|
-
end
|
236
|
-
|
237
|
-
# :nocov:
|
238
|
-
|
239
152
|
# Defines a pending test case.
|
240
153
|
#
|
241
154
|
# `&block` is never evaluated. It can be used to describe behaviour that is
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: r_spec-clone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-08-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: expresenter
|
@@ -30,28 +30,28 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.
|
33
|
+
version: 3.3.1
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.
|
40
|
+
version: 3.3.1
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: test_tube
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.1.
|
47
|
+
version: 2.1.3
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 2.1.
|
54
|
+
version: 2.1.3
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -188,7 +188,6 @@ files:
|
|
188
188
|
- README.md
|
189
189
|
- lib/r_spec.rb
|
190
190
|
- lib/r_spec/clone.rb
|
191
|
-
- lib/r_spec/clone/console.rb
|
192
191
|
- lib/r_spec/clone/dsl.rb
|
193
192
|
- lib/r_spec/clone/error.rb
|
194
193
|
- lib/r_spec/clone/error/pending_expectation.rb
|
@@ -203,6 +202,7 @@ files:
|
|
203
202
|
- lib/r_spec/clone/expectation_target/base.rb
|
204
203
|
- lib/r_spec/clone/expectation_target/block.rb
|
205
204
|
- lib/r_spec/clone/expectation_target/value.rb
|
205
|
+
- lib/r_spec/clone/logger.rb
|
206
206
|
homepage: https://r-spec.dev/
|
207
207
|
licenses:
|
208
208
|
- MIT
|
@@ -211,6 +211,7 @@ metadata:
|
|
211
211
|
documentation_uri: https://rubydoc.info/gems/r_spec-clone
|
212
212
|
source_code_uri: https://github.com/cyril/r_spec-clone.rb
|
213
213
|
wiki_uri: https://github.com/cyril/r_spec-clone.rb/wiki
|
214
|
+
rubygems_mfa_required: 'true'
|
214
215
|
post_install_message:
|
215
216
|
rdoc_options: []
|
216
217
|
require_paths:
|
@@ -219,14 +220,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
219
220
|
requirements:
|
220
221
|
- - ">="
|
221
222
|
- !ruby/object:Gem::Version
|
222
|
-
version:
|
223
|
+
version: 3.0.4
|
223
224
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
224
225
|
requirements:
|
225
226
|
- - ">="
|
226
227
|
- !ruby/object:Gem::Version
|
227
228
|
version: '0'
|
228
229
|
requirements: []
|
229
|
-
rubygems_version: 3.
|
230
|
+
rubygems_version: 3.2.33
|
230
231
|
signing_key:
|
231
232
|
specification_version: 4
|
232
233
|
summary: A minimalist RSpec clone
|