spectus 3.3.3 → 3.3.4
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 +111 -17
- data/lib/spectus.rb +91 -3
- data/lib/spectus/expectation_target.rb +4 -4
- data/lib/spectus/requirement_level/base.rb +5 -5
- data/lib/spectus/result.rb +3 -3
- data/lib/spectus/result/fail.rb +2 -0
- data/lib/spectus/result/pass.rb +2 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8767313f403c0f015d1316eabbf06f124ef4ecb136f8edf3529d533602622a8c
|
4
|
+
data.tar.gz: 419a5c0e93edac33135d305e9e384fea7d6ca305d68f9bd268f89d4ead020d3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 368fb8f488627e6c5b225bd66416ce4a3c8f61aaab0ce0a68ec6d2f354978393299399ccc4f9ea2c8e719b336764b9b7cededa4f6f237a7e5ad9a1495deb47ef
|
7
|
+
data.tar.gz: a5e56d1e3c6058f6df75bea0b5d564b0eb2cb6eea620ac9d445bea29a0a45e17302cdddf7cb9b5f7d18609c0b1334527f2495eef264bfb5d9041da453ec1055e
|
data/README.md
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
# Spectus
|
2
2
|
|
3
|
-
[]
|
4
|
-
[]
|
5
|
-
[][rubydoc]
|
3
|
+
[](https://travis-ci.org/fixrb/spectus)
|
4
|
+
[](https://rubygems.org/gems/spectus)
|
5
|
+
[](https://rubydoc.info/gems/spectus/frames)
|
7
6
|
|
8
|
-
> Expectation library with [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt)
|
7
|
+
> Expectation library with [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) requirement levels 🚥
|
9
8
|
|
10
9
|
## Installation
|
11
10
|
|
@@ -27,19 +26,102 @@ Or install it yourself as:
|
|
27
26
|
gem install spectus
|
28
27
|
```
|
29
28
|
|
29
|
+
## Overview
|
30
|
+
|
31
|
+
Assuming that an expectation is an assertion that is either `true` or `false`,
|
32
|
+
qualifying it with `MUST`, `SHOULD` and `MAY`, we can draw up several scenarios:
|
33
|
+
|
34
|
+
| Requirement levels | **MUST** | **SHOULD** | **MAY** |
|
35
|
+
| ------------------------- | -------- | ---------- | ------- |
|
36
|
+
| Implemented & Matched | `true` | `true` | `true` |
|
37
|
+
| Implemented & Not matched | `false` | `true` | `false` |
|
38
|
+
| Implemented & Exception | `false` | `false` | `false` |
|
39
|
+
| Not implemented | `false` | `false` | `true` |
|
40
|
+
|
41
|
+
When an expectation is evaluated by Spectus,
|
42
|
+
|
43
|
+
* in case of a _passed_ expectation, a `Spectus::Result::Pass` instance is _returned_;
|
44
|
+
* in case of a _failed_ expectation, a `Spectus::Result::Fail` exception is _raised_.
|
45
|
+
|
30
46
|
## Usage
|
31
47
|
|
32
|
-
|
48
|
+
The __Spectus__ library is basically a module containing an `it` instance method that accept a block representing the actual value to be evaluated through an expectation.
|
49
|
+
|
50
|
+
The `Spectus` module can be included inside a class and used as follows:
|
33
51
|
|
34
52
|
```ruby
|
35
|
-
|
53
|
+
require "spectus"
|
54
|
+
|
55
|
+
class Spec
|
56
|
+
include ::Spectus
|
57
|
+
|
58
|
+
attr_reader :subject
|
59
|
+
|
60
|
+
def initialize(subject)
|
61
|
+
@subject = subject
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_a
|
65
|
+
it { subject.upcase }.MUST eql "FOO"
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_b
|
69
|
+
it { subject.blank? }.MAY be_true
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_c
|
73
|
+
it { subject.length }.SHOULD equal 42
|
74
|
+
end
|
75
|
+
end
|
36
76
|
```
|
37
77
|
|
78
|
+
```ruby
|
79
|
+
t = Spec.new("foo")
|
80
|
+
|
81
|
+
t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
|
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)
|
84
|
+
|
85
|
+
t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
|
86
|
+
```
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
t = Spec.new(4)
|
90
|
+
|
91
|
+
t.test_a # => raises an exception:
|
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'
|
99
|
+
# Spectus::Result::Fail (NoMethodError: undefined method `upcase' for 4:Integer)
|
100
|
+
|
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)
|
102
|
+
|
103
|
+
t.test_c # => raises an exception:
|
104
|
+
# 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'
|
111
|
+
# Spectus::Result::Fail (NoMethodError: undefined method `length' for 4:Integer.)
|
112
|
+
```
|
113
|
+
|
114
|
+
## More examples
|
115
|
+
|
38
116
|
### Absolute Requirement
|
39
117
|
|
40
118
|
Given the "`ルビー`" object, when it receives `valid_encoding?` method, then it **MUST** be `true`:
|
41
119
|
|
42
120
|
```ruby
|
121
|
+
require "spectus"
|
122
|
+
|
123
|
+
include Spectus
|
124
|
+
|
43
125
|
it { "ルビー".valid_encoding? }.MUST be_true
|
44
126
|
# => Spectus::Result::Pass(actual: true, error: nil, expected: nil, got: true, matcher: :be_true, negate: false, level: :MUST, valid: true)
|
45
127
|
```
|
@@ -51,6 +133,10 @@ The result of the test shows that the spec passed.
|
|
51
133
|
Given the "`foo`" object, when it receives `length` method, then it **MUST NOT** raise the `NoMethodError` exception:
|
52
134
|
|
53
135
|
```ruby
|
136
|
+
require "spectus"
|
137
|
+
|
138
|
+
include Spectus
|
139
|
+
|
54
140
|
it { "foo".length }.MUST_NOT raise_exception NoMethodError
|
55
141
|
# => Spectus::Result::Pass(actual: 3, error: nil, expected: NoMethodError, got: true, matcher: :raise_exception, negate: true, level: :MUST, valid: true)
|
56
142
|
```
|
@@ -62,6 +148,10 @@ The result of the test shows that the spec passed.
|
|
62
148
|
Given the `BasicObject` object, when it receives `superclass` method, then it **SHOULD** return the explicit blank class `NilClass`:
|
63
149
|
|
64
150
|
```ruby
|
151
|
+
require "spectus"
|
152
|
+
|
153
|
+
include Spectus
|
154
|
+
|
65
155
|
it { BasicObject.superclass }.SHOULD equal NilClass
|
66
156
|
# => Spectus::Result::Pass(actual: nil, error: nil, expected: NilClass, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
|
67
157
|
```
|
@@ -74,6 +164,10 @@ However, because there isn't any exception, the result of the test shows that th
|
|
74
164
|
Given the "`1`" object, when it receives `+(1)` method, then it **SHOULD NOT** return the "`11`" value:
|
75
165
|
|
76
166
|
```ruby
|
167
|
+
require "spectus"
|
168
|
+
|
169
|
+
include Spectus
|
170
|
+
|
77
171
|
it { "1" + 1 }.SHOULD_NOT eql "11"
|
78
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)
|
79
173
|
```
|
@@ -85,17 +179,16 @@ There was a `TypeError` exception, the result of the test shows that the spec fa
|
|
85
179
|
Given the "`foo`" object, when it receives `blank?` method, then it **MAY** be `false`:
|
86
180
|
|
87
181
|
```ruby
|
182
|
+
require "spectus"
|
183
|
+
|
184
|
+
include Spectus
|
185
|
+
|
88
186
|
it { "foo".blank? }.MAY be_false
|
89
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)
|
90
188
|
```
|
91
189
|
|
92
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.
|
93
191
|
|
94
|
-
### More Examples
|
95
|
-
|
96
|
-
A full list of unit tests can be viewed (and executed) here:
|
97
|
-
[./test.rb](https://github.com/fixrb/spectus/blob/main/test.rb)
|
98
|
-
|
99
192
|
## Code Isolation
|
100
193
|
|
101
194
|
When executing expectations, side-effects may occur.
|
@@ -107,7 +200,10 @@ Because they may or may not be desired, each requirement level has 2 versions:
|
|
107
200
|
Example of test without isolation:
|
108
201
|
|
109
202
|
```ruby
|
203
|
+
require "spectus"
|
204
|
+
|
110
205
|
include Spectus
|
206
|
+
|
111
207
|
greeting = "Hello, world!"
|
112
208
|
it { greeting.gsub!("world", "Alice") }.MUST eql "Hello, Alice!"
|
113
209
|
# => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
|
@@ -117,7 +213,10 @@ greeting # => "Hello, Alice!"
|
|
117
213
|
Example of test in isolation:
|
118
214
|
|
119
215
|
```ruby
|
216
|
+
require "spectus"
|
217
|
+
|
120
218
|
include Spectus
|
219
|
+
|
121
220
|
greeting = "Hello, world!"
|
122
221
|
it { greeting.gsub!("world", "Alice") }.MUST! eql "Hello, Alice!"
|
123
222
|
# => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
|
@@ -145,8 +244,3 @@ The [gem](https://rubygems.org/gems/spectus) is available as open source under t
|
|
145
244
|
src="https://github.com/fixrb/spectus/raw/main/img/sashite.png"
|
146
245
|
alt="Sashite" /></a>
|
147
246
|
</p>
|
148
|
-
|
149
|
-
[gem]: https://rubygems.org/gems/spectus
|
150
|
-
[travis]: https://travis-ci.org/fixrb/spectus
|
151
|
-
[inchpages]: https://inch-ci.org/github/fixrb/spectus
|
152
|
-
[rubydoc]: https://rubydoc.info/gems/spectus/frames
|
data/lib/spectus.rb
CHANGED
@@ -2,11 +2,101 @@
|
|
2
2
|
|
3
3
|
require "matchi/helper"
|
4
4
|
|
5
|
+
require_relative File.join("spectus", "expectation_target")
|
6
|
+
|
5
7
|
# Namespace for the Spectus library.
|
6
8
|
#
|
7
|
-
#
|
9
|
+
# This module defines the {#it} method to create expectations, which can be
|
10
|
+
# automatically included into classes.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# class Spec
|
14
|
+
# include ::Spectus
|
15
|
+
#
|
16
|
+
# attr_reader :subject
|
17
|
+
#
|
18
|
+
# def initialize(subject)
|
19
|
+
# @subject = subject
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# def test_a
|
23
|
+
# it { subject.upcase }.MUST eql "FOO"
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# def test_b
|
27
|
+
# it { subject.blank? }.MAY be_true
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# def test_c
|
31
|
+
# it { subject.length }.SHOULD equal 42
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
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)
|
39
|
+
#
|
40
|
+
# Or even directly used like this.
|
41
|
+
#
|
42
|
+
# @example
|
8
43
|
# require 'spectus'
|
44
|
+
#
|
45
|
+
# include Spectus
|
46
|
+
#
|
9
47
|
# it { 42 }.MUST equal 42 # => #<Spectus::Result::Pass...>
|
48
|
+
#
|
49
|
+
# It also includes a collection of expectation matchers 🤹
|
50
|
+
#
|
51
|
+
# @example Equivalence matcher
|
52
|
+
# matcher = eql("foo") # => Matchi::Matcher::Eql.new("foo")
|
53
|
+
# matcher.matches? { "foo" } # => true
|
54
|
+
# matcher.matches? { "bar" } # => false
|
55
|
+
#
|
56
|
+
# @example Identity matcher
|
57
|
+
# object = "foo"
|
58
|
+
#
|
59
|
+
# matcher = equal(object) # => Matchi::Matcher::Equal.new(object)
|
60
|
+
# matcher.matches? { object } # => true
|
61
|
+
# matcher.matches? { "foo" } # => false
|
62
|
+
#
|
63
|
+
# @example Regular expressions matcher
|
64
|
+
# matcher = match(/^foo$/) # => Matchi::Matcher::Match.new(/^foo$/)
|
65
|
+
# matcher.matches? { "foo" } # => true
|
66
|
+
# matcher.matches? { "bar" } # => false
|
67
|
+
#
|
68
|
+
# @example Expecting errors matcher
|
69
|
+
# matcher = raise_exception(NameError) # => Matchi::Matcher::RaiseException.new(NameError)
|
70
|
+
# matcher.matches? { Boom } # => true
|
71
|
+
# matcher.matches? { true } # => false
|
72
|
+
#
|
73
|
+
# @example Truth matcher
|
74
|
+
# matcher = be_true # => Matchi::Matcher::BeTrue.new
|
75
|
+
# matcher.matches? { true } # => true
|
76
|
+
# matcher.matches? { false } # => false
|
77
|
+
# matcher.matches? { nil } # => false
|
78
|
+
# matcher.matches? { 4 } # => false
|
79
|
+
#
|
80
|
+
# @example Untruth matcher
|
81
|
+
# matcher = be_false # => Matchi::Matcher::BeFalse.new
|
82
|
+
# matcher.matches? { false } # => true
|
83
|
+
# matcher.matches? { true } # => false
|
84
|
+
# matcher.matches? { nil } # => false
|
85
|
+
# matcher.matches? { 4 } # => false
|
86
|
+
#
|
87
|
+
# @example Nil matcher
|
88
|
+
# matcher = be_nil # => Matchi::Matcher::BeNil.new
|
89
|
+
# matcher.matches? { nil } # => true
|
90
|
+
# matcher.matches? { false } # => false
|
91
|
+
# matcher.matches? { true } # => false
|
92
|
+
# matcher.matches? { 4 } # => false
|
93
|
+
#
|
94
|
+
# @example Type/class matcher
|
95
|
+
# matcher = be_an_instance_of(String) # => Matchi::Matcher::BeAnInstanceOf.new(String)
|
96
|
+
# matcher.matches? { "foo" } # => true
|
97
|
+
# matcher.matches? { 4 } # => false
|
98
|
+
#
|
99
|
+
# @see https://github.com/fixrb/matchi
|
10
100
|
module Spectus
|
11
101
|
include ::Matchi::Helper
|
12
102
|
|
@@ -22,5 +112,3 @@ module Spectus
|
|
22
112
|
ExpectationTarget.new(&input)
|
23
113
|
end
|
24
114
|
end
|
25
|
-
|
26
|
-
require_relative File.join("spectus", "expectation_target")
|
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative File.join("requirement_level", "must")
|
4
|
+
require_relative File.join("requirement_level", "should")
|
5
|
+
require_relative File.join("requirement_level", "may")
|
6
|
+
|
3
7
|
module Spectus
|
4
8
|
# Wraps the target of an expectation.
|
5
9
|
#
|
@@ -196,7 +200,3 @@ module Spectus
|
|
196
200
|
attr_reader :callable
|
197
201
|
end
|
198
202
|
end
|
199
|
-
|
200
|
-
require_relative File.join("requirement_level", "must")
|
201
|
-
require_relative File.join("requirement_level", "should")
|
202
|
-
require_relative File.join("requirement_level", "may")
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative File.join("..", "exam")
|
4
|
+
require_relative File.join("..", "result")
|
5
|
+
|
3
6
|
module Spectus
|
4
7
|
# Namespace for the requirement levels.
|
5
8
|
module RequirementLevel
|
@@ -32,8 +35,8 @@ module Spectus
|
|
32
35
|
|
33
36
|
# The result of the expectation.
|
34
37
|
#
|
35
|
-
# @raise [Spectus::Result::Fail] The expectation
|
36
|
-
# @return [Spectus::Result::Pass] The expectation
|
38
|
+
# @raise [Spectus::Result::Fail] The expectation failed.
|
39
|
+
# @return [Spectus::Result::Pass] The expectation passed.
|
37
40
|
def call
|
38
41
|
Result.call(pass?).with(
|
39
42
|
actual: exam.actual,
|
@@ -64,6 +67,3 @@ module Spectus
|
|
64
67
|
end
|
65
68
|
end
|
66
69
|
end
|
67
|
-
|
68
|
-
require_relative File.join("..", "exam")
|
69
|
-
require_relative File.join("..", "result")
|
data/lib/spectus/result.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative File.join("result", "fail")
|
4
|
+
require_relative File.join("result", "pass")
|
5
|
+
|
3
6
|
module Spectus
|
4
7
|
# Namespace for the results.
|
5
8
|
module Result
|
@@ -13,6 +16,3 @@ module Spectus
|
|
13
16
|
end
|
14
17
|
end
|
15
18
|
end
|
16
|
-
|
17
|
-
require_relative File.join("result", "fail")
|
18
|
-
require_relative File.join("result", "pass")
|
data/lib/spectus/result/fail.rb
CHANGED
@@ -5,6 +5,8 @@ require "expresenter/fail"
|
|
5
5
|
module Spectus
|
6
6
|
module Result
|
7
7
|
# The class that is responsible for reporting that the expectation is false.
|
8
|
+
#
|
9
|
+
# @see https://github.com/fixrb/expresenter/blob/v1.2.1/lib/expresenter/fail.rb
|
8
10
|
class Fail < ::Expresenter::Fail
|
9
11
|
end
|
10
12
|
end
|
data/lib/spectus/result/pass.rb
CHANGED
@@ -5,6 +5,8 @@ require "expresenter/pass"
|
|
5
5
|
module Spectus
|
6
6
|
module Result
|
7
7
|
# The class that is responsible for reporting that the expectation is true.
|
8
|
+
#
|
9
|
+
# @see https://github.com/fixrb/expresenter/blob/v1.2.1/lib/expresenter/pass.rb
|
8
10
|
class Pass < ::Expresenter::Pass
|
9
11
|
end
|
10
12
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spectus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.4
|
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-
|
11
|
+
date: 2021-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: defi
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 2.0
|
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: 2.0
|
54
|
+
version: 2.1.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: brutal
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|