r_spec-clone 1.2.1 → 1.3.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/README.md +50 -11
- data/lib/r_spec.rb +4 -4
- data/lib/r_spec/clone/dsl.rb +22 -12
- data/lib/r_spec/clone/error/pending_expectation.rb +7 -7
- data/lib/r_spec/clone/expectation_helper/it.rb +3 -3
- data/lib/r_spec/clone/expectation_helper/its.rb +1 -1
- data/lib/r_spec/clone/expectation_helper/shared.rb +186 -68
- data/lib/r_spec/clone/expectation_target.rb +2 -2
- data/lib/r_spec/clone/expectation_target/base.rb +42 -12
- data/lib/r_spec/clone/expectation_target/block.rb +6 -17
- data/lib/r_spec/clone/expectation_target/value.rb +6 -16
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8475d853643279af5a0a255bf7b3fd5b4547f4dd596bc044fa37a5ac2d69ff0
|
4
|
+
data.tar.gz: 3d22158ee01cb6f0e4924bd57345225e35d40920b2bffaf0cf862575db4b62ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f6826b996db0d6b3f727a7bc16b7757f7fc1ae350ca2285cf81aaf4ce8bfb15f0c37a8910bb2413800821524109cd6c655275aa2b800f52ba25aba1c31c9ac7
|
7
|
+
data.tar.gz: 53b85ef4eb8b249cdf2f717de35a6c29916c65d28a125e28656e300a5bfb7263d62865fba6d53a2517ae035cf64daa0c2b7b04a82ecaca93903502b0f5c2a59d
|
data/README.md
CHANGED
@@ -6,6 +6,7 @@ A minimalist __RSpec clone__ with all the essentials.
|
|
6
6
|
|
7
7
|
## Status
|
8
8
|
|
9
|
+
[](https://r-spec.dev/)
|
9
10
|
[](https://github.com/cyril/r_spec-clone.rb/releases)
|
10
11
|
[](https://rubydoc.info/github/cyril/r_spec-clone.rb/main)
|
11
12
|
[](https://github.com/cyril/r_spec-clone.rb/actions?query=workflow%3Aci+branch%3Amain)
|
@@ -23,7 +24,7 @@ A minimalist __RSpec clone__ with all the essentials.
|
|
23
24
|
|
24
25
|
* There is no option to activate monkey-patching.
|
25
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.
|
26
|
-
*
|
27
|
+
* Malicious _actual values_ cannot [hack results](https://asciinema.org/a/423547?autoplay=1&speed=2).
|
27
28
|
* If no `subject` has been explicitly determined, none is defined.
|
28
29
|
* If no described class is set, `described_class` is undefined instead of `nil`.
|
29
30
|
* Expectations cannot be added inside a `before` block.
|
@@ -95,12 +96,28 @@ For unit tests, it is recommended to follow the conventions for method names:
|
|
95
96
|
|
96
97
|
To establish certain contexts — think _empty array_ versus _array with elements_ — the `context` method may be used to communicate this to the reader.
|
97
98
|
|
98
|
-
|
99
|
+
To execute unit tests while isolating side effects in a sub-process, declined methods can be used: `describe!`, `context!`, `it!`, `its!`. Here is an example:
|
99
100
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
```ruby
|
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
121
|
|
105
122
|
### Expectations
|
106
123
|
|
@@ -132,13 +149,13 @@ expect(actual).to match(expected) # passes if expected.match?(actual)
|
|
132
149
|
expect { actual }.to raise_exception(expected) # passes if expected exception is raised
|
133
150
|
```
|
134
151
|
|
135
|
-
####
|
152
|
+
#### True
|
136
153
|
|
137
154
|
```ruby
|
138
155
|
expect(actual).to be_true # passes if true.equal?(actual)
|
139
156
|
```
|
140
157
|
|
141
|
-
####
|
158
|
+
#### False
|
142
159
|
|
143
160
|
```ruby
|
144
161
|
expect(actual).to be_false # passes if false.equal?(actual)
|
@@ -157,6 +174,21 @@ expect(actual).to be_instance_of(expected) # passes if expected.equal?(actual
|
|
157
174
|
expect(actual).to be_an_instance_of(expected) # passes if expected.equal?(actual.class)
|
158
175
|
```
|
159
176
|
|
177
|
+
#### Change
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
expect { object.action }.to change(object, :value).from(old).to(new)
|
181
|
+
expect { object.action }.to change(object, :value).by(delta)
|
182
|
+
expect { object.action }.to change(object, :value).by_at_least(minimum_delta)
|
183
|
+
expect { object.action }.to change(object, :value).by_at_most(maximum_delta)
|
184
|
+
```
|
185
|
+
|
186
|
+
#### Satisfy
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
expect(actual).to(satisfy { |value| value == expected })
|
190
|
+
```
|
191
|
+
|
160
192
|
### Running specs
|
161
193
|
|
162
194
|
By convention, specs live in the `spec/` directory of a project. Spec files should end with `_spec.rb` to be recognizable as such.
|
@@ -217,17 +249,23 @@ bundle exec rake
|
|
217
249
|
|
218
250
|
## Performance
|
219
251
|
|
252
|
+
The benchmarks compare the performance of [`r_spec-clone`](https://rubygems.org/gems/r_spec-clone) with the following frameworks (in alphabetical order):
|
253
|
+
|
254
|
+
* [`fix`](https://rubygems.org/gems/fix)
|
255
|
+
* [`minitest`](https://rubygems.org/gems/minitest)
|
256
|
+
* [`rspec`](https://rubygems.org/gems/rspec)
|
257
|
+
|
220
258
|
### Boot time
|
221
259
|
|
222
260
|
Benchmark against [100 executions of a file containing 1 expectation](https://github.com/cyril/r_spec-clone.rb/blob/main/benchmark/boot_time/) (lower is better).
|
223
261
|
|
224
|
-

|
262
|
+

|
225
263
|
|
226
|
-
###
|
264
|
+
### Runtime
|
227
265
|
|
228
266
|
Benchmark against [1 execution of a file containing 1,000,000 expectations](https://github.com/cyril/r_spec-clone.rb/blob/main/benchmark/run_time/) (lower is better).
|
229
267
|
|
230
|
-

|
231
269
|
|
232
270
|
## Test suite
|
233
271
|
|
@@ -237,6 +275,7 @@ __RSpec clone__'s specifications are self-described here: [spec/](https://github
|
|
237
275
|
|
238
276
|
* Home page: [https://r-spec.dev/](https://r-spec.dev/)
|
239
277
|
* Cheatsheet: [https://r-spec.dev/cheatsheet.html](https://r-spec.dev/cheatsheet.html)
|
278
|
+
* Blog post: [https://batman.buzz/introducing-a-new-rspec-850d48c0f901](https://batman.buzz/introducing-a-new-rspec-850d48c0f901)
|
240
279
|
* Source code: [https://github.com/cyril/r_spec-clone.rb](https://github.com/cyril/r_spec-clone.rb)
|
241
280
|
* API Doc: [https://rubydoc.info/gems/r_spec-clone](https://rubydoc.info/gems/r_spec-clone)
|
242
281
|
* Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
|
data/lib/r_spec.rb
CHANGED
@@ -37,8 +37,8 @@ require_relative File.join("r_spec", "clone", "dsl")
|
|
37
37
|
#
|
38
38
|
# # Output to the console
|
39
39
|
# # Success: expected to eq 3.
|
40
|
-
# # Success: expected
|
41
|
-
# # Success: expected
|
40
|
+
# # Success: expected to be true.
|
41
|
+
# # Success: expected to be false.
|
42
42
|
#
|
43
43
|
# @example An inherited definition of let
|
44
44
|
# require "r_spec"
|
@@ -201,8 +201,8 @@ module RSpec
|
|
201
201
|
# @param name [String, nil] The name of the spec.
|
202
202
|
# @param block [Proc] An expectation to evaluate.
|
203
203
|
#
|
204
|
-
# @raise (see RSpec::ExpectationTarget::Base#result)
|
205
|
-
# @return (see RSpec::ExpectationTarget::Base#result)
|
204
|
+
# @raise (see RSpec::Clone::ExpectationTarget::Base#result)
|
205
|
+
# @return (see RSpec::Clone::ExpectationTarget::Base#result)
|
206
206
|
def self.it(name = nil, &block)
|
207
207
|
Clone::Dsl.it(name, &block)
|
208
208
|
end
|
data/lib/r_spec/clone/dsl.rb
CHANGED
@@ -329,8 +329,7 @@ module RSpec
|
|
329
329
|
#
|
330
330
|
# @api public
|
331
331
|
def self.it(_name = nil, &block)
|
332
|
-
|
333
|
-
run(example, &block)
|
332
|
+
run(example_without_attribute.new, &block)
|
334
333
|
end
|
335
334
|
|
336
335
|
# :nocov:
|
@@ -417,15 +416,7 @@ module RSpec
|
|
417
416
|
#
|
418
417
|
# @api public
|
419
418
|
def self.its(attribute, *args, **kwargs, &block)
|
420
|
-
|
421
|
-
include ExpectationHelper::Its
|
422
|
-
|
423
|
-
define_method(:actual) do
|
424
|
-
subject.public_send(attribute, *args, **kwargs)
|
425
|
-
end
|
426
|
-
end.new
|
427
|
-
|
428
|
-
run(example, &block)
|
419
|
+
run(example_with_attribute(attribute, *args, **kwargs).new, &block)
|
429
420
|
end
|
430
421
|
|
431
422
|
# :nocov:
|
@@ -495,6 +486,25 @@ module RSpec
|
|
495
486
|
Console.passed_spec Error::PendingExpectation.result(message)
|
496
487
|
end
|
497
488
|
|
489
|
+
# Example class for concrete test case.
|
490
|
+
def self.example_without_attribute
|
491
|
+
::Class.new(self) do
|
492
|
+
prepend ExpectationHelper::It
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
# Example class for concrete test case that specifies the actual value of
|
497
|
+
# an attribute of the subject.
|
498
|
+
def self.example_with_attribute(attribute, *args, **kwargs)
|
499
|
+
::Class.new(self) do
|
500
|
+
prepend ExpectationHelper::Its
|
501
|
+
|
502
|
+
define_method(:actual) do
|
503
|
+
subject.public_send(attribute, *args, **kwargs)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
498
508
|
# Creates a subprocess and runs the block inside.
|
499
509
|
def self.fork!(&block)
|
500
510
|
pid = fork(&block)
|
@@ -514,7 +524,7 @@ module RSpec
|
|
514
524
|
example&.send(AFTER_METHOD)
|
515
525
|
end
|
516
526
|
|
517
|
-
private_class_method :fork!, :run
|
527
|
+
private_class_method :example_without_attribute, :example_with_attribute, :fork!, :run
|
518
528
|
|
519
529
|
private
|
520
530
|
|
@@ -12,13 +12,13 @@ module RSpec
|
|
12
12
|
# @return [nil] Write a pending expectation to STDOUT.
|
13
13
|
def self.result(message)
|
14
14
|
::Expresenter.call(true).with(
|
15
|
-
actual:
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
negate:
|
21
|
-
level:
|
15
|
+
actual: new(message),
|
16
|
+
definition: "raise exception #{self}",
|
17
|
+
error: nil,
|
18
|
+
expected: self,
|
19
|
+
got: false,
|
20
|
+
negate: true,
|
21
|
+
level: :SHOULD
|
22
22
|
)
|
23
23
|
end
|
24
24
|
end
|
@@ -18,8 +18,8 @@ module RSpec
|
|
18
18
|
# @return [Block, Value] The wrapped target of an expectation.
|
19
19
|
#
|
20
20
|
# @example
|
21
|
-
# expect("foo") # => #<RSpec::ExpectationTarget::Value:
|
22
|
-
# expect { Boom } # => #<RSpec::ExpectationTarget::Block:
|
21
|
+
# expect("foo") # => #<RSpec::Clone::ExpectationTarget::Value:0x00007f @actual="foo">
|
22
|
+
# expect { Boom } # => #<RSpec::Clone::ExpectationTarget::Block:0x00007f @callable=#<Proc:0x00007f>>
|
23
23
|
#
|
24
24
|
# @api public
|
25
25
|
def expect(value = self.class.superclass, &block)
|
@@ -31,7 +31,7 @@ module RSpec
|
|
31
31
|
# @return [Block] The wrapped target of an expectation.
|
32
32
|
#
|
33
33
|
# @example
|
34
|
-
# is_expected # => #<RSpec::ExpectationTarget::Block:
|
34
|
+
# is_expected # => #<RSpec::Clone::ExpectationTarget::Block:0x00007fb6b8 @callable=#<Proc:0x00007fb6b8>>
|
35
35
|
#
|
36
36
|
# @api public
|
37
37
|
def is_expected
|
@@ -15,7 +15,7 @@ module RSpec
|
|
15
15
|
# @return [Block] The wrapped target of an expectation.
|
16
16
|
#
|
17
17
|
# @example
|
18
|
-
# is_expected # => #<RSpec::ExpectationTarget::Block:
|
18
|
+
# is_expected # => #<RSpec::Clone::ExpectationTarget::Block:0x00007f @callable=#<Proc:0x00007f>>
|
19
19
|
#
|
20
20
|
# @api public
|
21
21
|
def is_expected
|
@@ -1,83 +1,201 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "matchi
|
4
|
-
|
5
|
-
require_relative File.join("..", "error", "pending_expectation")
|
3
|
+
require "matchi"
|
6
4
|
|
7
5
|
module RSpec
|
8
6
|
module Clone
|
9
7
|
module ExpectationHelper
|
10
8
|
# Abstract expectation helper base module.
|
11
9
|
#
|
12
|
-
# This module defines a number of methods to create expectations, which
|
13
|
-
# automatically included into examples.
|
14
|
-
#
|
15
|
-
# It also includes a collection of expectation matchers 🤹
|
16
|
-
#
|
17
|
-
# @example Equivalence matcher
|
18
|
-
# matcher = eql("foo") # => Matchi::Matcher::Eql.new("foo")
|
19
|
-
# matcher.matches? { "foo" } # => true
|
20
|
-
# matcher.matches? { "bar" } # => false
|
21
|
-
#
|
22
|
-
# matcher = eq("foo") # => Matchi::Matcher::Eq.new("foo")
|
23
|
-
# matcher.matches? { "foo" } # => true
|
24
|
-
# matcher.matches? { "bar" } # => false
|
25
|
-
#
|
26
|
-
# @example Identity matcher
|
27
|
-
# object = "foo"
|
28
|
-
#
|
29
|
-
# matcher = equal(object) # => Matchi::Matcher::Equal.new(object)
|
30
|
-
# matcher.matches? { object } # => true
|
31
|
-
# matcher.matches? { "foo" } # => false
|
32
|
-
#
|
33
|
-
# matcher = be(object) # => Matchi::Matcher::Be.new(object)
|
34
|
-
# matcher.matches? { object } # => true
|
35
|
-
# matcher.matches? { "foo" } # => false
|
36
|
-
#
|
37
|
-
# @example Regular expressions matcher
|
38
|
-
# matcher = match(/^foo$/) # => Matchi::Matcher::Match.new(/^foo$/)
|
39
|
-
# matcher.matches? { "foo" } # => true
|
40
|
-
# matcher.matches? { "bar" } # => false
|
41
|
-
#
|
42
|
-
# @example Expecting errors matcher
|
43
|
-
# matcher = raise_exception(NameError) # => Matchi::Matcher::RaiseException.new(NameError)
|
44
|
-
# matcher.matches? { Boom } # => true
|
45
|
-
# matcher.matches? { true } # => false
|
46
|
-
#
|
47
|
-
# @example Truth matcher
|
48
|
-
# matcher = be_true # => Matchi::Matcher::BeTrue.new
|
49
|
-
# matcher.matches? { true } # => true
|
50
|
-
# matcher.matches? { false } # => false
|
51
|
-
# matcher.matches? { nil } # => false
|
52
|
-
# matcher.matches? { 4 } # => false
|
53
|
-
#
|
54
|
-
# @example Untruth matcher
|
55
|
-
# matcher = be_false # => Matchi::Matcher::BeFalse.new
|
56
|
-
# matcher.matches? { false } # => true
|
57
|
-
# matcher.matches? { true } # => false
|
58
|
-
# matcher.matches? { nil } # => false
|
59
|
-
# matcher.matches? { 4 } # => false
|
60
|
-
#
|
61
|
-
# @example Nil matcher
|
62
|
-
# matcher = be_nil # => Matchi::Matcher::BeNil.new
|
63
|
-
# matcher.matches? { nil } # => true
|
64
|
-
# matcher.matches? { false } # => false
|
65
|
-
# matcher.matches? { true } # => false
|
66
|
-
# matcher.matches? { 4 } # => false
|
10
|
+
# This module defines a number of methods to create expectations, which
|
11
|
+
# are automatically included into examples.
|
67
12
|
#
|
68
|
-
#
|
69
|
-
# matcher = be_instance_of(String) # => Matchi::Matcher::BeInstanceOf.new(String)
|
70
|
-
# matcher.matches? { "foo" } # => true
|
71
|
-
# matcher.matches? { 4 } # => false
|
72
|
-
#
|
73
|
-
# matcher = be_an_instance_of(String) # => Matchi::Matcher::BeAnInstanceOf.new(String)
|
74
|
-
# matcher.matches? { "foo" } # => true
|
75
|
-
# matcher.matches? { 4 } # => false
|
13
|
+
# It also includes a collection of expectation matchers.
|
76
14
|
#
|
77
15
|
# @see https://github.com/fixrb/matchi
|
78
|
-
# @see https://github.com/fixrb/matchi-rspec
|
79
16
|
module Shared
|
80
|
-
|
17
|
+
# Equivalence matcher
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# matcher = eq("foo")
|
21
|
+
# matcher.matches? { "foo" } # => true
|
22
|
+
# matcher.matches? { "bar" } # => false
|
23
|
+
#
|
24
|
+
# @param expected [#eql?] An expected equivalent object.
|
25
|
+
#
|
26
|
+
# @return [#matches?] An equivalence matcher.
|
27
|
+
#
|
28
|
+
# @api public
|
29
|
+
def eq(expected)
|
30
|
+
::Matchi::Eq.new(expected)
|
31
|
+
end
|
32
|
+
|
33
|
+
alias eql eq
|
34
|
+
|
35
|
+
# Identity matcher
|
36
|
+
#
|
37
|
+
# @example
|
38
|
+
# object = "foo"
|
39
|
+
# matcher = be(object)
|
40
|
+
# matcher.matches? { object } # => true
|
41
|
+
# matcher.matches? { "foo" } # => false
|
42
|
+
#
|
43
|
+
# @param expected [#equal?] The expected identical object.
|
44
|
+
#
|
45
|
+
# @return [#matches?] An identity matcher.
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def be(expected)
|
49
|
+
::Matchi::Be.new(expected)
|
50
|
+
end
|
51
|
+
|
52
|
+
alias equal be
|
53
|
+
|
54
|
+
# Regular expressions matcher
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# matcher = match(/^foo$/)
|
58
|
+
# matcher.matches? { "foo" } # => true
|
59
|
+
# matcher.matches? { "bar" } # => false
|
60
|
+
#
|
61
|
+
# @param expected [#match] A regular expression.
|
62
|
+
#
|
63
|
+
# @return [#matches?] A regular expression matcher.
|
64
|
+
#
|
65
|
+
# @api public
|
66
|
+
def match(expected)
|
67
|
+
::Matchi::Match.new(expected)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Expecting errors matcher
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# matcher = raise_exception(NameError)
|
74
|
+
# matcher.matches? { Boom } # => true
|
75
|
+
# matcher.matches? { true } # => false
|
76
|
+
#
|
77
|
+
# @param expected [Exception, #to_s] The expected exception name.
|
78
|
+
#
|
79
|
+
# @return [#matches?] An error matcher.
|
80
|
+
#
|
81
|
+
# @api public
|
82
|
+
def raise_exception(expected)
|
83
|
+
::Matchi::RaiseException.new(expected)
|
84
|
+
end
|
85
|
+
|
86
|
+
# True matcher
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# matcher = be_true
|
90
|
+
# matcher.matches? { true } # => true
|
91
|
+
# matcher.matches? { false } # => false
|
92
|
+
# matcher.matches? { nil } # => false
|
93
|
+
# matcher.matches? { 4 } # => false
|
94
|
+
#
|
95
|
+
# @return [#matches?] A `true` matcher.
|
96
|
+
#
|
97
|
+
# @api public
|
98
|
+
def be_true
|
99
|
+
be(true)
|
100
|
+
end
|
101
|
+
|
102
|
+
# False matcher
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# matcher = be_false
|
106
|
+
# matcher.matches? { false } # => true
|
107
|
+
# matcher.matches? { true } # => false
|
108
|
+
# matcher.matches? { nil } # => false
|
109
|
+
# matcher.matches? { 4 } # => false
|
110
|
+
#
|
111
|
+
# @return [#matches?] A `false` matcher.
|
112
|
+
#
|
113
|
+
# @api public
|
114
|
+
def be_false
|
115
|
+
be(false)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Nil matcher
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# matcher = be_nil
|
122
|
+
# matcher.matches? { nil } # => true
|
123
|
+
# matcher.matches? { false } # => false
|
124
|
+
# matcher.matches? { true } # => false
|
125
|
+
# matcher.matches? { 4 } # => false
|
126
|
+
#
|
127
|
+
# @return [#matches?] A `nil` matcher.
|
128
|
+
#
|
129
|
+
# @api public
|
130
|
+
def be_nil
|
131
|
+
be(nil)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Type/class matcher
|
135
|
+
#
|
136
|
+
# @example
|
137
|
+
# matcher = be_an_instance_of(String)
|
138
|
+
# matcher.matches? { "foo" } # => true
|
139
|
+
# matcher.matches? { 4 } # => false
|
140
|
+
#
|
141
|
+
# @param expected [Class, #to_s] The expected class name.
|
142
|
+
#
|
143
|
+
# @return [#matches?] A type/class matcher.
|
144
|
+
#
|
145
|
+
# @api public
|
146
|
+
def be_an_instance_of(expected)
|
147
|
+
::Matchi::BeAnInstanceOf.new(expected)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Change matcher
|
151
|
+
#
|
152
|
+
# @example
|
153
|
+
# object = []
|
154
|
+
# matcher = change(object, :length).by(1)
|
155
|
+
# matcher.matches? { object << 1 } # => true
|
156
|
+
#
|
157
|
+
# object = []
|
158
|
+
# matcher = change(object, :length).by_at_least(1)
|
159
|
+
# matcher.matches? { object << 1 } # => true
|
160
|
+
#
|
161
|
+
# object = []
|
162
|
+
# matcher = change(object, :length).by_at_most(1)
|
163
|
+
# matcher.matches? { object << 1 } # => true
|
164
|
+
#
|
165
|
+
# object = "foo"
|
166
|
+
# matcher = change(object, :to_s).from("foo").to("FOO")
|
167
|
+
# matcher.matches? { object.upcase! } # => true
|
168
|
+
#
|
169
|
+
# object = "foo"
|
170
|
+
# matcher = change(object, :to_s).to("FOO")
|
171
|
+
# matcher.matches? { object.upcase! } # => true
|
172
|
+
#
|
173
|
+
# @param object [#object_id] An object.
|
174
|
+
# @param method [Symbol] The name of a method.
|
175
|
+
# @param args [Array] A list of arguments.
|
176
|
+
# @param kwargs [Hash] A list of keyword arguments.
|
177
|
+
#
|
178
|
+
# @return [#matches?] A change matcher.
|
179
|
+
#
|
180
|
+
# @api public
|
181
|
+
def change(object, method, *args, **kwargs, &block)
|
182
|
+
::Matchi::Change.new(object, method, *args, **kwargs, &block)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Satisfy matcher
|
186
|
+
#
|
187
|
+
# @example
|
188
|
+
# matcher = satisfy { |value| value == 42 }
|
189
|
+
# matcher.matches? { 42 } # => true
|
190
|
+
#
|
191
|
+
# @param expected [Proc] A block of code.
|
192
|
+
#
|
193
|
+
# @return [#matches?] A satisfy matcher.
|
194
|
+
#
|
195
|
+
# @api public
|
196
|
+
def satisfy(&expected)
|
197
|
+
::Matchi::Satisfy.new(&expected)
|
198
|
+
end
|
81
199
|
end
|
82
200
|
end
|
83
201
|
end
|
@@ -8,8 +8,8 @@ module RSpec
|
|
8
8
|
# Wraps the target of an expectation.
|
9
9
|
module ExpectationTarget
|
10
10
|
# @param undefined_value A sentinel value to be able to tell when the user
|
11
|
-
# did not pass an argument. We can't use `nil` for that because `nil` is
|
12
|
-
# valid value to pass.
|
11
|
+
# did not pass an argument. We can't use `nil` for that because `nil` is
|
12
|
+
# a valid value to pass.
|
13
13
|
# @param value [#object_id, nil] An actual value.
|
14
14
|
# @param block [#call, nil] A code to evaluate.
|
15
15
|
#
|
@@ -10,14 +10,14 @@ module RSpec
|
|
10
10
|
module ExpectationTarget
|
11
11
|
# Abstract expectation target base class.
|
12
12
|
#
|
13
|
-
# @note `RSpec::ExpectationTarget::Base` is not intended to be
|
14
|
-
# directly by users. Use `expect` instead.
|
13
|
+
# @note `RSpec::Clone::ExpectationTarget::Base` is not intended to be
|
14
|
+
# instantiated directly by users. Use `expect` instead.
|
15
15
|
class Base
|
16
16
|
# Instantiate a new expectation target.
|
17
17
|
#
|
18
|
-
# @param
|
19
|
-
def initialize(
|
20
|
-
@
|
18
|
+
# @param input [#object_id, Proc] The code to evaluate.
|
19
|
+
def initialize(input)
|
20
|
+
@input = input
|
21
21
|
end
|
22
22
|
|
23
23
|
# Runs the given expectation, passing if `matcher` returns true.
|
@@ -52,6 +52,36 @@ module RSpec
|
|
52
52
|
|
53
53
|
protected
|
54
54
|
|
55
|
+
# @param test [::TestTube::Base] The state of the experiment.
|
56
|
+
# @param matcher [#matches?] The matcher.
|
57
|
+
# @param negate [Boolean] The assertion is positive or negative.
|
58
|
+
#
|
59
|
+
# @return [nil] Write a message to STDOUT.
|
60
|
+
#
|
61
|
+
# @raise [SystemExit] Terminate execution immediately by calling
|
62
|
+
# `Kernel.exit(false)` with a failure message written to STDERR.
|
63
|
+
def absolute_requirement(test, matcher:, negate:)
|
64
|
+
result(
|
65
|
+
passed?(test),
|
66
|
+
actual: test.actual,
|
67
|
+
error: test.error,
|
68
|
+
got: test.got,
|
69
|
+
matcher: matcher,
|
70
|
+
negate: negate
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Code experiment result.
|
75
|
+
#
|
76
|
+
# @param test [::TestTube::Base] The state of the experiment.
|
77
|
+
#
|
78
|
+
# @see https://github.com/fixrb/test_tube
|
79
|
+
#
|
80
|
+
# @return [Boolean] The result of the test (passed or failed).
|
81
|
+
def passed?(test)
|
82
|
+
test.got.equal?(true)
|
83
|
+
end
|
84
|
+
|
55
85
|
# @param passed [Boolean] The high expectation passed or failed.
|
56
86
|
# @param actual [#object_id] The actual value.
|
57
87
|
# @param error [Exception, nil] Any raised exception.
|
@@ -65,13 +95,13 @@ module RSpec
|
|
65
95
|
# `Kernel.exit(false)` with a failure message written to STDERR.
|
66
96
|
def result(passed, actual:, error:, got:, matcher:, negate:)
|
67
97
|
Console.passed_spec ::Expresenter.call(passed).with(
|
68
|
-
actual:
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
level:
|
98
|
+
actual: actual,
|
99
|
+
definition: matcher.to_s,
|
100
|
+
error: error,
|
101
|
+
expected: matcher.expected,
|
102
|
+
got: got,
|
103
|
+
negate: negate,
|
104
|
+
level: :MUST
|
75
105
|
)
|
76
106
|
rescue ::Expresenter::Fail => e
|
77
107
|
Console.failed_spec(e)
|
@@ -16,31 +16,20 @@ module RSpec
|
|
16
16
|
# # with `not_to`
|
17
17
|
# expect { actual }.not_to be(4)
|
18
18
|
#
|
19
|
-
# @note `RSpec::ExpectationTarget::Block` is not intended to be
|
20
|
-
# directly by users. Use `expect` instead.
|
19
|
+
# @note `RSpec::Clone::ExpectationTarget::Block` is not intended to be
|
20
|
+
# instantiated directly by users. Use `expect` instead.
|
21
21
|
class Block < Base
|
22
22
|
protected
|
23
23
|
|
24
24
|
# @param matcher [#matches?] The matcher.
|
25
25
|
# @param negate [Boolean] The assertion is positive or negative.
|
26
26
|
#
|
27
|
-
# @return
|
27
|
+
# @return (see Base#absolute_requirement)
|
28
28
|
#
|
29
|
-
# @raise
|
30
|
-
# `Kernel.exit(false)` with a failure message written to STDERR.
|
29
|
+
# @raise (see Base#absolute_requirement)
|
31
30
|
def absolute_requirement(matcher:, negate:)
|
32
|
-
|
33
|
-
|
34
|
-
isolation: false,
|
35
|
-
matcher: matcher,
|
36
|
-
negate: negate
|
37
|
-
)
|
38
|
-
|
39
|
-
result(
|
40
|
-
experiment.got.equal?(true),
|
41
|
-
actual: experiment.actual,
|
42
|
-
error: experiment.error,
|
43
|
-
got: experiment.got,
|
31
|
+
super(
|
32
|
+
::TestTube.invoke(isolate: false, matcher: matcher, negate: negate, &@input),
|
44
33
|
matcher: matcher,
|
45
34
|
negate: negate
|
46
35
|
)
|
@@ -16,30 +16,20 @@ module RSpec
|
|
16
16
|
# # with `not_to`
|
17
17
|
# expect(actual).not_to be(4)
|
18
18
|
#
|
19
|
-
# @note `RSpec::ExpectationTarget::Value` is not intended to be
|
20
|
-
# directly by users. Use `expect` instead.
|
19
|
+
# @note `RSpec::Clone::ExpectationTarget::Value` is not intended to be
|
20
|
+
# instantiated directly by users. Use `expect` instead.
|
21
21
|
class Value < Base
|
22
22
|
protected
|
23
23
|
|
24
24
|
# @param matcher [#matches?] The matcher.
|
25
25
|
# @param negate [Boolean] The assertion is positive or negative.
|
26
26
|
#
|
27
|
-
# @return
|
27
|
+
# @return (see Base#absolute_requirement)
|
28
28
|
#
|
29
|
-
# @raise
|
30
|
-
# `Kernel.exit(false)` with a failure message written to STDERR.
|
29
|
+
# @raise (see Base#absolute_requirement)
|
31
30
|
def absolute_requirement(matcher:, negate:)
|
32
|
-
|
33
|
-
@
|
34
|
-
matcher: matcher,
|
35
|
-
negate: negate
|
36
|
-
)
|
37
|
-
|
38
|
-
result(
|
39
|
-
experiment.got.equal?(true),
|
40
|
-
actual: experiment.actual,
|
41
|
-
error: experiment.error,
|
42
|
-
got: experiment.got,
|
31
|
+
super(
|
32
|
+
::TestTube.pass(@input, matcher: matcher, negate: negate),
|
43
33
|
matcher: matcher,
|
44
34
|
negate: negate
|
45
35
|
)
|
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.3.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: 2021-07-
|
11
|
+
date: 2021-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: expresenter
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.
|
19
|
+
version: 1.4.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.
|
26
|
+
version: 1.4.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: matchi
|
28
|
+
name: matchi
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 1.1
|
33
|
+
version: 3.1.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: 1.1
|
40
|
+
version: 3.1.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:
|
47
|
+
version: 2.1.0
|
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:
|
54
|
+
version: 2.1.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|