spectus 3.3.4 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8767313f403c0f015d1316eabbf06f124ef4ecb136f8edf3529d533602622a8c
4
- data.tar.gz: 419a5c0e93edac33135d305e9e384fea7d6ca305d68f9bd268f89d4ead020d3c
3
+ metadata.gz: 2fea4a88991addc0a6b69ce46d6422e92df818447818975d6123848cbba9d5a7
4
+ data.tar.gz: 8dffb97e6e58cdf0c3e5661294238e42f5477f4e677a34868ce918156086cbdb
5
5
  SHA512:
6
- metadata.gz: 368fb8f488627e6c5b225bd66416ce4a3c8f61aaab0ce0a68ec6d2f354978393299399ccc4f9ea2c8e719b336764b9b7cededa4f6f237a7e5ad9a1495deb47ef
7
- data.tar.gz: a5e56d1e3c6058f6df75bea0b5d564b0eb2cb6eea620ac9d445bea29a0a45e17302cdddf7cb9b5f7d18609c0b1334527f2495eef264bfb5d9041da453ec1055e
6
+ metadata.gz: 9a4798a255dcf0097dcba1bac46af91552a11348513c0d4af77a00a748cb950e90b113c264404cc745af3c7dc730154ad81893d879a495450f6cda5ca4b07942
7
+ data.tar.gz: ba56345d554c0483ce27fd6c7d876e7837d59a53a37a9b9e6417df849e0a6047b522a2c00e7f5d4327a76c1ed3e60cea68cff5970e7dcc4718d31ed89e3e6fa4
data/README.md CHANGED
@@ -38,7 +38,7 @@ qualifying it with `MUST`, `SHOULD` and `MAY`, we can draw up several scenarios:
38
38
  | Implemented & Exception | `false` | `false` | `false` |
39
39
  | Not implemented | `false` | `false` | `true` |
40
40
 
41
- When an expectation is evaluated by Spectus,
41
+ When an expectation is evaluated by __Spectus__,
42
42
 
43
43
  * in case of a _passed_ expectation, a `Spectus::Result::Pass` instance is _returned_;
44
44
  * in case of a _failed_ expectation, a `Spectus::Result::Fail` exception is _raised_.
@@ -78,11 +78,11 @@ end
78
78
  ```ruby
79
79
  t = Spec.new("foo")
80
80
 
81
- t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
81
+ t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST)
82
82
 
83
- t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY, valid: false)
83
+ t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY)
84
84
 
85
- t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
85
+ t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD)
86
86
  ```
87
87
 
88
88
  ```ruby
@@ -90,104 +90,87 @@ t = Spec.new(4)
90
90
 
91
91
  t.test_a # => raises an exception:
92
92
  # Traceback (most recent call last):
93
- # 6: from ./bin/console:8:in `<main>'
94
- # 5: from (irb):23
95
- # 4: from (irb):11:in `test_a'
96
- # 3: from /Users/cyril/github/fixrb/spectus/lib/spectus/expectation_target.rb:34:in `MUST'
97
- # 2: from /Users/cyril/github/fixrb/spectus/lib/spectus/requirement_level/base.rb:38:in `call'
98
- # 1: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/expresenter-1.2.1/lib/expresenter/fail.rb:19:in `with'
93
+ # 3: from ./bin/console:8:in `<main>'
94
+ # 2: from (irb):23
95
+ # 1: from (irb):11:in `test_a'
99
96
  # Spectus::Result::Fail (NoMethodError: undefined method `upcase' for 4:Integer)
100
97
 
101
- t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for 4:Integer>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY, valid: false)
98
+ t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for 4:Integer>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY)
102
99
 
103
100
  t.test_c # => raises an exception:
104
101
  # Traceback (most recent call last):
105
- # 6: from ./bin/console:8:in `<main>'
106
- # 5: from (irb):25
107
- # 4: from (irb):19:in `test_c'
108
- # 3: from /Users/cyril/github/fixrb/spectus/lib/spectus/expectation_target.rb:100:in `SHOULD'
109
- # 2: from /Users/cyril/github/fixrb/spectus/lib/spectus/requirement_level/base.rb:38:in `call'
110
- # 1: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/expresenter-1.2.1/lib/expresenter/fail.rb:19:in `with'
102
+ # 3: from ./bin/console:8:in `<main>'
103
+ # 2: from (irb):25
104
+ # 1: from (irb):19:in `test_c'
111
105
  # Spectus::Result::Fail (NoMethodError: undefined method `length' for 4:Integer.)
112
106
  ```
113
107
 
114
108
  ## More examples
115
109
 
116
- ### Absolute Requirement
117
-
118
- Given the "`ルビー`" object, when it receives `valid_encoding?` method, then it **MUST** be `true`:
110
+ To make __Spectus__ available:
119
111
 
120
112
  ```ruby
121
113
  require "spectus"
122
114
 
123
115
  include Spectus
124
-
125
- it { "ルビー".valid_encoding? }.MUST be_true
126
- # => Spectus::Result::Pass(actual: true, error: nil, expected: nil, got: true, matcher: :be_true, negate: false, level: :MUST, valid: true)
127
116
  ```
128
117
 
129
- The result of the test shows that the spec passed.
118
+ All examples here assume that this has been done.
130
119
 
131
- ### Absolute Prohibition
120
+ ### Absolute Requirement
132
121
 
133
- Given the "`foo`" object, when it receives `length` method, then it **MUST NOT** raise the `NoMethodError` exception:
122
+ There's only one bat:
134
123
 
135
124
  ```ruby
136
- require "spectus"
125
+ it { "🦇".size }.MUST equal 1
126
+ # => Spectus::Result::Pass(actual: 1, error: nil, expected: 1, got: true, matcher: :equal, negate: false, level: :MUST)
127
+ ```
137
128
 
138
- include Spectus
129
+ ### Absolute Prohibition
139
130
 
140
- it { "foo".length }.MUST_NOT raise_exception NoMethodError
141
- # => Spectus::Result::Pass(actual: 3, error: nil, expected: NoMethodError, got: true, matcher: :raise_exception, negate: true, level: :MUST, valid: true)
142
- ```
131
+ The true from the false:
143
132
 
144
- The result of the test shows that the spec passed.
133
+ ```ruby
134
+ it { false }.MUST_NOT be_true
135
+ # => Spectus::Result::Pass(actual: false, error: nil, expected: nil, got: true, matcher: :be_true, negate: true, level: :MUST)
136
+ ```
145
137
 
146
138
  ### Recommended
147
139
 
148
- Given the `BasicObject` object, when it receives `superclass` method, then it **SHOULD** return the explicit blank class `NilClass`:
140
+ A well-known joke. An addition of `0.1` and `0.2` is deadly precise:
149
141
 
150
142
  ```ruby
151
- require "spectus"
152
-
153
- include Spectus
154
-
155
- it { BasicObject.superclass }.SHOULD equal NilClass
156
- # => Spectus::Result::Pass(actual: nil, error: nil, expected: NilClass, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
143
+ it { 0.1 + 0.2 }.SHOULD equal 0.3
144
+ # => Spectus::Result::Pass(actual: 0.30000000000000004, error: nil, expected: 0.3, got: false, matcher: :equal, negate: false, level: :SHOULD)
157
145
  ```
158
146
 
159
- Instead of the expected `NilClass` class, its sole instance (which is `nil`) was returned.
160
- However, because there isn't any exception, the result of the test shows that the spec passed.
161
-
162
147
  ### Not Recommended
163
148
 
164
- Given the "`1`" object, when it receives `+(1)` method, then it **SHOULD NOT** return the "`11`" value:
149
+ The situation should still be under control:
165
150
 
166
151
  ```ruby
167
- require "spectus"
168
-
169
- include Spectus
170
-
171
- it { "1" + 1 }.SHOULD_NOT eql "11"
172
- # raise Spectus::Result::Fail(actual: nil, error: #<TypeError: no implicit conversion of Integer into String>, expected: "11", got: nil, matcher: :eql, negate: true, level: :SHOULD, valid: false)
152
+ it { BOOM }.SHOULD_NOT raise_exception SystemExit
173
153
  ```
174
154
 
175
- There was a `TypeError` exception, the result of the test shows that the spec failed.
155
+ ```txt
156
+ Traceback (most recent call last):
157
+ 2: from ./bin/console:8:in `<main>'
158
+ 1: from (irb):8
159
+ Spectus::Result::Fail (NameError: uninitialized constant BOOM.)
160
+ ```
176
161
 
177
162
  ### Optional
178
163
 
179
- Given the "`foo`" object, when it receives `blank?` method, then it **MAY** be `false`:
164
+ An empty array is blank, right?
180
165
 
181
166
  ```ruby
182
- require "spectus"
183
-
184
- include Spectus
185
-
186
- it { "foo".blank? }.MAY be_false
187
- # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_false, negate: false, level: :MAY, valid: false)
167
+ it { [].blank? }.MAY be_true
168
+ # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for []:Array>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY)
188
169
  ```
189
170
 
190
- The optional `blank?` method is not implemented (unlike in [Ruby on Rails](https://api.rubyonrails.org/classes/Object.html#method-i-blank-3F), for instance), so the result of the test shows that the spec passed.
171
+ Damn, I forgot to load activesupport. 🤦‍♂️
172
+
173
+ That said, the test is passing due to the _not-implemented-like_ raised exception: `NoMethodError`.
191
174
 
192
175
  ## Code Isolation
193
176
 
@@ -200,26 +183,22 @@ Because they may or may not be desired, each requirement level has 2 versions:
200
183
  Example of test without isolation:
201
184
 
202
185
  ```ruby
203
- require "spectus"
204
-
205
- include Spectus
206
-
207
186
  greeting = "Hello, world!"
187
+
208
188
  it { greeting.gsub!("world", "Alice") }.MUST eql "Hello, Alice!"
209
- # => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
189
+ # => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST)
190
+
210
191
  greeting # => "Hello, Alice!"
211
192
  ```
212
193
 
213
194
  Example of test in isolation:
214
195
 
215
196
  ```ruby
216
- require "spectus"
217
-
218
- include Spectus
219
-
220
197
  greeting = "Hello, world!"
198
+
221
199
  it { greeting.gsub!("world", "Alice") }.MUST! eql "Hello, Alice!"
222
- # => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
200
+ # => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST)
201
+
223
202
  greeting # => "Hello, world!"
224
203
  ```
225
204
 
data/lib/spectus.rb CHANGED
@@ -33,9 +33,9 @@ require_relative File.join("spectus", "expectation_target")
33
33
  # end
34
34
  #
35
35
  # t = Spec.new("foo")
36
- # t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
37
- # t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY, valid: false)
38
- # t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
36
+ # t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST)
37
+ # t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY)
38
+ # t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD)
39
39
  #
40
40
  # Or even directly used like this.
41
41
  #
@@ -44,7 +44,7 @@ require_relative File.join("spectus", "expectation_target")
44
44
  #
45
45
  # include Spectus
46
46
  #
47
- # it { 42 }.MUST equal 42 # => #<Spectus::Result::Pass...>
47
+ # it { 42 }.MUST equal 42 # => Spectus::Result::Pass(actual: 42, error: nil, expected: 42, got: true, matcher: :equal, negate: false, level: :MUST
48
48
  #
49
49
  # It also includes a collection of expectation matchers 🤹
50
50
  #
@@ -103,7 +103,7 @@ module Spectus
103
103
  # Expectations are built with this method.
104
104
  #
105
105
  # @example An _absolute requirement_ definition.
106
- # it { 42 }.MUST equal 42 # => #<Spectus::Result::Pass...>
106
+ # it { 42 }.MUST equal 42 # => Spectus::Result::Pass(actual: 42, error: nil, expected: 42, got: true, matcher: :equal, negate: false, level: :MUST
107
107
  #
108
108
  # @param input [Proc] The code to test.
109
109
  #
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative File.join("..", "exam")
3
+ require "test_tube"
4
+
4
5
  require_relative File.join("..", "result")
5
6
 
6
7
  module Spectus
@@ -12,22 +13,21 @@ module Spectus
12
13
  #
13
14
  # @param callable [#call] The callable object to test.
14
15
  # @param isolation [Boolean] Compute actual in isolation?
15
- # @param negate [Boolean] Positive or negative assertion?
16
+ # @param negate [Boolean] Invert the matcher or not.
16
17
  # @param matcher [#matches?] The matcher.
17
- def initialize(callable:, isolation:, negate:, matcher:)
18
- @negate = negate
19
- @matcher = matcher
20
-
21
- @exam = Exam.new(
22
- callable: callable,
18
+ def initialize(callable:, isolation:, matcher:, negate:)
19
+ @negate = negate
20
+ @matcher = matcher
21
+ @experiment = ::TestTube.invoke(
22
+ callable,
23
23
  isolation: isolation,
24
- negate: negate,
25
- matcher: matcher
24
+ matcher: matcher,
25
+ negate: negate
26
26
  )
27
27
  end
28
28
 
29
- # @return [#Exam] The exam.
30
- attr_reader :exam
29
+ # @return [TestTube::Base] The experiment.
30
+ attr_reader :experiment
31
31
 
32
32
  # @return [#matches?] The matcher that performed a boolean comparison
33
33
  # between the actual value and the expected value.
@@ -39,20 +39,21 @@ module Spectus
39
39
  # @return [Spectus::Result::Pass] The expectation passed.
40
40
  def call
41
41
  Result.call(pass?).with(
42
- actual: exam.actual,
43
- error: exam.exception,
42
+ actual: experiment.actual,
43
+ error: experiment.error,
44
44
  expected: matcher.expected,
45
- got: exam.got,
46
- negate: negate?,
47
- valid: exam.valid?,
45
+ got: experiment.got,
46
+ level: level,
48
47
  matcher: matcher.class.to_sym,
49
- level: level
48
+ negate: negate?
50
49
  )
51
50
  end
52
51
 
53
52
  protected
54
53
 
55
- # @return [Symbol] The requirement level.
54
+ # Some key words for use in RFCs to indicate requirement levels.
55
+ #
56
+ # @return [:MUST, :SHOULD, :MAY] The requirement level.
56
57
  def level
57
58
  self.class.name.split("::").fetch(-1).upcase.to_sym
58
59
  end
@@ -60,7 +61,7 @@ module Spectus
60
61
  # @note The boolean comparison between the actual value and the expected
61
62
  # value can be evaluated to a negative assertion.
62
63
  #
63
- # @return [Boolean] Positive or negative assertion?
64
+ # @return [Boolean] Invert the matcher or not.
64
65
  def negate?
65
66
  @negate
66
67
  end
@@ -10,7 +10,7 @@ module Spectus
10
10
  #
11
11
  # @return [Boolean] Report if the low expectation pass or fail?
12
12
  def pass?
13
- super || exam.exception.is_a?(::NoMethodError)
13
+ super || experiment.error.is_a?(::NoMethodError)
14
14
  end
15
15
  end
16
16
  end
@@ -10,7 +10,7 @@ module Spectus
10
10
  #
11
11
  # @return [Boolean] Report if the high expectation pass or fail?
12
12
  def pass?
13
- exam.valid?
13
+ experiment.got.equal?(true)
14
14
  end
15
15
  end
16
16
  end
@@ -10,7 +10,7 @@ module Spectus
10
10
  #
11
11
  # @return [Boolean] Report if the medium expectation pass or fail?
12
12
  def pass?
13
- super || exam.exception.nil?
13
+ super || experiment.error.nil?
14
14
  end
15
15
  end
16
16
  end
metadata CHANGED
@@ -1,57 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spectus
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.4
4
+ version: 3.4.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-06-16 00:00:00.000000000 Z
11
+ date: 2021-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: defi
14
+ name: expresenter
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.0.5
19
+ version: 1.3.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: 2.0.5
26
+ version: 1.3.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: expresenter
28
+ name: matchi
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2.1
33
+ version: 2.1.0
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.2.1
40
+ version: 2.1.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: matchi
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.0
47
+ version: 1.0.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: 2.1.0
54
+ version: 1.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: brutal
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -187,7 +187,6 @@ files:
187
187
  - LICENSE.md
188
188
  - README.md
189
189
  - lib/spectus.rb
190
- - lib/spectus/exam.rb
191
190
  - lib/spectus/expectation_target.rb
192
191
  - lib/spectus/requirement_level/base.rb
193
192
  - lib/spectus/requirement_level/may.rb
data/lib/spectus/exam.rb DELETED
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "defi"
4
-
5
- module Spectus
6
- # This class evaluate the expectation with the passed block.
7
- class Exam
8
- # Execute the untested code from the passed block against the matcher.
9
- #
10
- # rubocop:disable Lint/RescueException
11
- #
12
- # @param callable [#call] The callable object to test.
13
- # @param isolation [Boolean] Compute actual in isolation?
14
- # @param negate [Boolean] Positive or negative assertion?
15
- # @param matcher [#matches?] The matcher.
16
- def initialize(callable:, isolation:, negate:, matcher:)
17
- @got = negate ^ matcher.matches? do
18
- value = if isolation
19
- send_call.to!(callable)
20
- else
21
- send_call.to(callable)
22
- end
23
-
24
- @actual = value.object
25
-
26
- value.call
27
- end
28
- rescue ::Exception => e
29
- @actual = nil
30
- @exception = e
31
- end
32
- # rubocop:enable Lint/RescueException
33
-
34
- # @return [#object_id] The actual value.
35
- attr_reader :actual
36
-
37
- # @return [Exception, nil] An exception.
38
- attr_reader :exception
39
-
40
- # @return [Boolean, nil] Report to the spec requirement level if the
41
- # expectation is true or false.
42
- attr_reader :got
43
-
44
- # @return [Defi::Challenge] The challenge for the callable object.
45
- def send_call
46
- ::Defi.send(:call)
47
- end
48
-
49
- # Report to the spec requirement level if the test pass or fail.
50
- #
51
- # @return [Boolean] Report if the test pass or fail?
52
- def valid?
53
- exception.nil? ? got : false
54
- end
55
- end
56
- end