spectus 3.4.0 → 4.0.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 +39 -93
- data/lib/spectus.rb +214 -102
- data/lib/spectus/requirement.rb +13 -0
- data/lib/spectus/requirement/base.rb +81 -0
- data/lib/spectus/requirement/optional.rb +28 -0
- data/lib/spectus/requirement/recommended.rb +28 -0
- data/lib/spectus/requirement/required.rb +17 -0
- metadata +18 -21
- data/lib/spectus/expectation_target.rb +0 -202
- data/lib/spectus/requirement_level/base.rb +0 -70
- data/lib/spectus/requirement_level/may.rb +0 -17
- data/lib/spectus/requirement_level/must.rb +0 -17
- data/lib/spectus/requirement_level/should.rb +0 -17
- data/lib/spectus/result.rb +0 -18
- data/lib/spectus/result/fail.rb +0 -13
- data/lib/spectus/result/pass.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 82d7608bd88d8d56331cb54a2d8f52969d235acecc443d97b46f0285202a6bcd
|
4
|
+
data.tar.gz: c7a19799743076dcd75eefa1d760b07fd325b579f4d43bbc74dd2bc3b75cd48d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e82f4d736d40ff0a9aec7343a49998873ee6c3e43af63fc55d46503b72f786957591bdf84bfe2d1d04a4135983e4156e81904f28deb3897a1d9335d8427910c0
|
7
|
+
data.tar.gz: 467587719b23f2c0ca39292a077d96a10ff8042fea7f0a2d72afcd4b02661b97114e50696cced7b740425d33b0da6c37baf2d7563fae1fdad6eadebb2319d400
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# Spectus
|
2
2
|
|
3
|
-
[](https://github.com/fixrb/spectus/releases)
|
4
|
+
[](https://rubydoc.info/github/fixrb/spectus/main)
|
5
|
+
[](https://github.com/fixrb/spectus/actions?query=workflow%3Aci+branch%3Amain)
|
6
|
+
[](https://github.com/fixrb/spectus/actions?query=workflow%3Arubocop+branch%3Amain)
|
7
|
+
[](https://github.com/fixrb/spectus/raw/main/LICENSE.md)
|
6
8
|
|
7
9
|
> Expectation library with [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) requirement levels 🚥
|
8
10
|
|
@@ -26,93 +28,26 @@ Or install it yourself as:
|
|
26
28
|
gem install spectus
|
27
29
|
```
|
28
30
|
|
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
|
-
|
46
31
|
## Usage
|
47
32
|
|
48
|
-
The __Spectus__ library is basically a module
|
33
|
+
The __Spectus__ library is basically a module defining methods that can be used to qualify expectations in specifications.
|
49
34
|
|
50
|
-
|
35
|
+
To make __Spectus__ available:
|
51
36
|
|
52
37
|
```ruby
|
53
38
|
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
|
76
39
|
```
|
77
40
|
|
78
|
-
|
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)
|
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)
|
41
|
+
For convenience, we will also instantiate some matchers from the [Matchi library](https://github.com/fixrb/matchi):
|
84
42
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
```ruby
|
89
|
-
t = Spec.new(4)
|
90
|
-
|
91
|
-
t.test_a # => raises an exception:
|
92
|
-
# Traceback (most recent call last):
|
93
|
-
# 3: from ./bin/console:8:in `<main>'
|
94
|
-
# 2: from (irb):23
|
95
|
-
# 1: from (irb):11:in `test_a'
|
96
|
-
# Spectus::Result::Fail (NoMethodError: undefined method `upcase' for 4:Integer)
|
97
|
-
|
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)
|
99
|
-
|
100
|
-
t.test_c # => raises an exception:
|
101
|
-
# Traceback (most recent call last):
|
102
|
-
# 3: from ./bin/console:8:in `<main>'
|
103
|
-
# 2: from (irb):25
|
104
|
-
# 1: from (irb):19:in `test_c'
|
105
|
-
# Spectus::Result::Fail (NoMethodError: undefined method `length' for 4:Integer.)
|
43
|
+
```sh
|
44
|
+
gem install matchi
|
106
45
|
```
|
107
46
|
|
108
|
-
## More examples
|
109
|
-
|
110
|
-
To make __Spectus__ available:
|
111
|
-
|
112
47
|
```ruby
|
113
|
-
require "
|
48
|
+
require "matchi/helper"
|
114
49
|
|
115
|
-
include
|
50
|
+
include Matchi::Helper
|
116
51
|
```
|
117
52
|
|
118
53
|
All examples here assume that this has been done.
|
@@ -122,8 +57,9 @@ All examples here assume that this has been done.
|
|
122
57
|
There's only one bat:
|
123
58
|
|
124
59
|
```ruby
|
125
|
-
|
126
|
-
|
60
|
+
definition = Spectus.must equal 1
|
61
|
+
definition.call { "🦇".size }
|
62
|
+
# => Expresenter::Pass(actual: 1, error: nil, expected: 1, got: true, matcher: :equal, negate: false, level: :MUST
|
127
63
|
```
|
128
64
|
|
129
65
|
### Absolute Prohibition
|
@@ -131,8 +67,9 @@ it { "🦇".size }.MUST equal 1
|
|
131
67
|
The true from the false:
|
132
68
|
|
133
69
|
```ruby
|
134
|
-
|
135
|
-
|
70
|
+
definition = Spectus.must_not be_true
|
71
|
+
definition.call { false }
|
72
|
+
# => Expresenter::Pass(actual: false, error: nil, expected: nil, got: true, matcher: :be_true, negate: true, level: :MUST
|
136
73
|
```
|
137
74
|
|
138
75
|
### Recommended
|
@@ -140,8 +77,9 @@ it { false }.MUST_NOT be_true
|
|
140
77
|
A well-known joke. An addition of `0.1` and `0.2` is deadly precise:
|
141
78
|
|
142
79
|
```ruby
|
143
|
-
|
144
|
-
|
80
|
+
definition = Spectus.should equal 0.3
|
81
|
+
definition.call { 0.1 + 0.2 }
|
82
|
+
# => Expresenter::Pass(actual: 0.30000000000000004, error: nil, expected: 0.3, got: false, matcher: :equal, negate: false, level: :SHOULD
|
145
83
|
```
|
146
84
|
|
147
85
|
### Not Recommended
|
@@ -149,14 +87,19 @@ it { 0.1 + 0.2 }.SHOULD equal 0.3
|
|
149
87
|
The situation should still be under control:
|
150
88
|
|
151
89
|
```ruby
|
152
|
-
|
90
|
+
definition = Spectus.should_not raise_exception SystemExit
|
91
|
+
definition.call { BOOM }
|
153
92
|
```
|
154
93
|
|
155
94
|
```txt
|
156
95
|
Traceback (most recent call last):
|
157
|
-
|
158
|
-
|
159
|
-
|
96
|
+
6: from /Users/cyril/.rbenv/versions/2.7.3/bin/irb:23:in `<main>'
|
97
|
+
5: from /Users/cyril/.rbenv/versions/2.7.3/bin/irb:23:in `load'
|
98
|
+
4: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/irb-1.2.6/exe/irb:11:in `<top (required)>'
|
99
|
+
3: from (irb):11
|
100
|
+
2: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/spectus-4.0.0/lib/spectus/requirement/base.rb:32:in `call'
|
101
|
+
1: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/expresenter-1.3.0/lib/expresenter/fail.rb:25:in `with'
|
102
|
+
Expresenter::Fail (NameError: uninitialized constant BOOM.)
|
160
103
|
```
|
161
104
|
|
162
105
|
### Optional
|
@@ -164,8 +107,9 @@ Spectus::Result::Fail (NameError: uninitialized constant BOOM.)
|
|
164
107
|
An empty array is blank, right?
|
165
108
|
|
166
109
|
```ruby
|
167
|
-
|
168
|
-
|
110
|
+
definition = Spectus.may be_true
|
111
|
+
definition.call { [].blank? }
|
112
|
+
# => Expresenter::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for []:Array>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY
|
169
113
|
```
|
170
114
|
|
171
115
|
Damn, I forgot to load activesupport. 🤦♂️
|
@@ -185,8 +129,9 @@ Example of test without isolation:
|
|
185
129
|
```ruby
|
186
130
|
greeting = "Hello, world!"
|
187
131
|
|
188
|
-
|
189
|
-
|
132
|
+
definition = Spectus.must eql "Hello, Alice!"
|
133
|
+
definition.call { greeting.gsub!("world", "Alice") }
|
134
|
+
# => Expresenter::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST
|
190
135
|
|
191
136
|
greeting # => "Hello, Alice!"
|
192
137
|
```
|
@@ -196,8 +141,9 @@ Example of test in isolation:
|
|
196
141
|
```ruby
|
197
142
|
greeting = "Hello, world!"
|
198
143
|
|
199
|
-
|
200
|
-
|
144
|
+
definition = Spectus.must! eql "Hello, Alice!"
|
145
|
+
definition.call { greeting.gsub!("world", "Alice") }
|
146
|
+
# => Expresenter::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST
|
201
147
|
|
202
148
|
greeting # => "Hello, world!"
|
203
149
|
```
|
data/lib/spectus.rb
CHANGED
@@ -1,114 +1,226 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require_relative File.join("spectus", "expectation_target")
|
3
|
+
require_relative File.join("spectus", "requirement")
|
6
4
|
|
7
5
|
# Namespace for the Spectus library.
|
8
6
|
#
|
9
|
-
# This module defines
|
10
|
-
#
|
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)
|
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
|
-
#
|
40
|
-
# Or even directly used like this.
|
41
|
-
#
|
42
|
-
# @example
|
43
|
-
# require 'spectus'
|
44
|
-
#
|
45
|
-
# include Spectus
|
46
|
-
#
|
47
|
-
# it { 42 }.MUST equal 42 # => Spectus::Result::Pass(actual: 42, error: nil, expected: 42, got: true, matcher: :equal, negate: false, level: :MUST
|
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
|
7
|
+
# This module defines methods that can be used to qualify expectations in
|
8
|
+
# specifications.
|
100
9
|
module Spectus
|
101
|
-
|
10
|
+
# This method mean that the definition is an absolute requirement of the specification.
|
11
|
+
#
|
12
|
+
# @example An absolute requirement definition
|
13
|
+
# require "spectus"
|
14
|
+
# require "matchi/helper"
|
15
|
+
#
|
16
|
+
# include Matchi::Helper
|
17
|
+
#
|
18
|
+
# Spectus.must eql "FOO"
|
19
|
+
# # => #<MUST Matchi::Matcher::Eql("FOO") isolate=false negate=false>
|
20
|
+
#
|
21
|
+
# @param matcher [#matches?] The matcher.
|
22
|
+
#
|
23
|
+
# @return [Requirement::Required] An absolute requirement level instance.
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def self.must(matcher)
|
27
|
+
Requirement::Required.new(
|
28
|
+
isolate: false,
|
29
|
+
negate: false,
|
30
|
+
matcher: matcher
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @example An absolute requirement definition with isolation
|
35
|
+
# require "spectus"
|
36
|
+
# require "matchi/helper"
|
37
|
+
#
|
38
|
+
# include Matchi::Helper
|
39
|
+
#
|
40
|
+
# Spectus.must! eql "FOO"
|
41
|
+
# # => #<MUST Matchi::Matcher::Eql("FOO") isolate=true negate=false>
|
42
|
+
#
|
43
|
+
# @see must
|
44
|
+
def self.must!(matcher)
|
45
|
+
Requirement::Required.new(
|
46
|
+
isolate: true,
|
47
|
+
negate: false,
|
48
|
+
matcher: matcher
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
# This method mean that the definition is an absolute prohibition of the specification.
|
53
|
+
#
|
54
|
+
# @example An absolute prohibition definition
|
55
|
+
# require "spectus"
|
56
|
+
# require "matchi/helper"
|
57
|
+
#
|
58
|
+
# include Matchi::Helper
|
59
|
+
#
|
60
|
+
# Spectus.must_not equal 42
|
61
|
+
# # => #<MUST Matchi::Matcher::Equal(42) isolate=false negate=true>
|
62
|
+
#
|
63
|
+
# @param matcher [#matches?] The matcher.
|
64
|
+
#
|
65
|
+
# @return [Requirement::Required] An absolute prohibition level instance.
|
66
|
+
def self.must_not(matcher)
|
67
|
+
Requirement::Required.new(
|
68
|
+
isolate: false,
|
69
|
+
negate: true,
|
70
|
+
matcher: matcher
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @example An absolute prohibition definition with isolation
|
75
|
+
# require "spectus"
|
76
|
+
# require "matchi/helper"
|
77
|
+
#
|
78
|
+
# include Matchi::Helper
|
79
|
+
#
|
80
|
+
# Spectus.must_not! equal 42
|
81
|
+
# # => #<MUST Matchi::Matcher::Equal(42) isolate=true negate=true>
|
82
|
+
#
|
83
|
+
# @see must_not
|
84
|
+
def self.must_not!(matcher)
|
85
|
+
Requirement::Required.new(
|
86
|
+
isolate: true,
|
87
|
+
negate: true,
|
88
|
+
matcher: matcher
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
# This method mean that there may exist valid reasons in particular
|
93
|
+
# circumstances to ignore a particular item, but the full implications must be
|
94
|
+
# understood and carefully weighed before choosing a different course.
|
95
|
+
#
|
96
|
+
# @example A recommended definition
|
97
|
+
# require "spectus"
|
98
|
+
# require "matchi/helper"
|
99
|
+
#
|
100
|
+
# include Matchi::Helper
|
101
|
+
#
|
102
|
+
# Spectus.should equal true
|
103
|
+
# # => #<SHOULD Matchi::Matcher::Equal(true) isolate=false negate=false>
|
104
|
+
#
|
105
|
+
# @param matcher [#matches?] The matcher.
|
106
|
+
#
|
107
|
+
# @return [Requirement::Recommended] A recommended requirement level instance.
|
108
|
+
def self.should(matcher)
|
109
|
+
Requirement::Recommended.new(
|
110
|
+
isolate: false,
|
111
|
+
negate: false,
|
112
|
+
matcher: matcher
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
# @example A recommended definition with isolation
|
117
|
+
# require "spectus"
|
118
|
+
# require "matchi/helper"
|
119
|
+
#
|
120
|
+
# include Matchi::Helper
|
121
|
+
#
|
122
|
+
# Spectus.should! equal true
|
123
|
+
# # => #<SHOULD Matchi::Matcher::Equal(true) isolate=true negate=false>
|
124
|
+
#
|
125
|
+
# @see should
|
126
|
+
def self.should!(matcher)
|
127
|
+
Requirement::Recommended.new(
|
128
|
+
isolate: true,
|
129
|
+
negate: false,
|
130
|
+
matcher: matcher
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
# This method mean that there may exist valid reasons in particular
|
135
|
+
# circumstances when the particular behavior is acceptable or even useful, but
|
136
|
+
# the full implications should be understood and the case carefully weighed
|
137
|
+
# before implementing any behavior described with this label.
|
138
|
+
#
|
139
|
+
# @example A not recommended definition
|
140
|
+
# require "spectus"
|
141
|
+
# require "matchi/helper"
|
142
|
+
#
|
143
|
+
# include Matchi::Helper
|
144
|
+
#
|
145
|
+
# Spectus.should_not raise_exception NoMethodError
|
146
|
+
# # => #<SHOULD Matchi::Matcher::RaiseException(NoMethodError) isolate=false negate=true>
|
147
|
+
#
|
148
|
+
# @param matcher [#matches?] The matcher.
|
149
|
+
#
|
150
|
+
# @return [Requirement::Recommended] A not recommended requirement level
|
151
|
+
# instance.
|
152
|
+
def self.should_not(matcher)
|
153
|
+
Requirement::Recommended.new(
|
154
|
+
isolate: false,
|
155
|
+
negate: true,
|
156
|
+
matcher: matcher
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
# @example A not recommended definition with isolation
|
161
|
+
# require "spectus"
|
162
|
+
# require "matchi/helper"
|
163
|
+
#
|
164
|
+
# include Matchi::Helper
|
165
|
+
#
|
166
|
+
# Spectus.should_not! raise_exception NoMethodError
|
167
|
+
# # => #<SHOULD Matchi::Matcher::RaiseException(NoMethodError) isolate=true negate=true>
|
168
|
+
#
|
169
|
+
# @see should_not
|
170
|
+
def self.should_not!(matcher)
|
171
|
+
Requirement::Recommended.new(
|
172
|
+
isolate: true,
|
173
|
+
negate: true,
|
174
|
+
matcher: matcher
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
# This method mean that an item is truly optional.
|
179
|
+
# One vendor may choose to include the item because a particular marketplace
|
180
|
+
# requires it or because the vendor feels that it enhances the product while
|
181
|
+
# another vendor may omit the same item. An implementation which does not
|
182
|
+
# include a particular option must be prepared to interoperate with another
|
183
|
+
# implementation which does include the option, though perhaps with reduced
|
184
|
+
# functionality. In the same vein an implementation which does include a
|
185
|
+
# particular option must be prepared to interoperate with another
|
186
|
+
# implementation which does not include the option (except, of course, for the
|
187
|
+
# feature the option provides).
|
188
|
+
#
|
189
|
+
# @example An optional definition
|
190
|
+
# require "spectus"
|
191
|
+
# require "matchi/helper"
|
192
|
+
#
|
193
|
+
# include Matchi::Helper
|
194
|
+
#
|
195
|
+
# Spectus.may match /^foo$/
|
196
|
+
# # => #<MAY Matchi::Matcher::Match(/^foo$/) isolate=false negate=false>
|
197
|
+
#
|
198
|
+
# @param matcher [#matches?] The matcher.
|
199
|
+
#
|
200
|
+
# @return [Requirement::Optional] An optional requirement level instance.
|
201
|
+
def self.may(matcher)
|
202
|
+
Requirement::Optional.new(
|
203
|
+
isolate: false,
|
204
|
+
negate: false,
|
205
|
+
matcher: matcher
|
206
|
+
)
|
207
|
+
end
|
102
208
|
|
103
|
-
#
|
209
|
+
# @example An optional definition with isolation
|
210
|
+
# require "spectus"
|
211
|
+
# require "matchi/helper"
|
104
212
|
#
|
105
|
-
#
|
106
|
-
# it { 42 }.MUST equal 42 # => Spectus::Result::Pass(actual: 42, error: nil, expected: 42, got: true, matcher: :equal, negate: false, level: :MUST
|
213
|
+
# include Matchi::Helper
|
107
214
|
#
|
108
|
-
#
|
215
|
+
# Spectus.may! match /^foo$/
|
216
|
+
# # => #<MAY Matchi::Matcher::Match(/^foo$/) isolate=true negate=false>
|
109
217
|
#
|
110
|
-
# @
|
111
|
-
def
|
112
|
-
|
218
|
+
# @see may
|
219
|
+
def self.may!(matcher)
|
220
|
+
Requirement::Optional.new(
|
221
|
+
isolate: true,
|
222
|
+
negate: false,
|
223
|
+
matcher: matcher
|
224
|
+
)
|
113
225
|
end
|
114
226
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spectus
|
4
|
+
# Namespace for the results.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
module Requirement
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require_relative File.join("requirement", "required")
|
12
|
+
require_relative File.join("requirement", "recommended")
|
13
|
+
require_relative File.join("requirement", "optional")
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "expresenter"
|
4
|
+
require "test_tube"
|
5
|
+
|
6
|
+
module Spectus
|
7
|
+
# Namespace for the requirement levels.
|
8
|
+
module Requirement
|
9
|
+
# Requirement level's base class.
|
10
|
+
class Base
|
11
|
+
# Initialize the requirement level class.
|
12
|
+
#
|
13
|
+
# @param isolate [Boolean] Compute actual in a subprocess.
|
14
|
+
# @param matcher [#matches?] The matcher.
|
15
|
+
# @param negate [Boolean] Invert the matcher or not.
|
16
|
+
def initialize(isolate:, matcher:, negate:)
|
17
|
+
@isolate = isolate
|
18
|
+
@matcher = matcher
|
19
|
+
@negate = negate
|
20
|
+
end
|
21
|
+
|
22
|
+
# Test result.
|
23
|
+
#
|
24
|
+
# @raise [::Expresenter::Fail] A failed spec exception.
|
25
|
+
# @return [::Expresenter::Pass] A passed spec instance.
|
26
|
+
#
|
27
|
+
# @see https://github.com/fixrb/expresenter
|
28
|
+
#
|
29
|
+
# @api public
|
30
|
+
def call(&block)
|
31
|
+
test = ::TestTube.invoke(isolation: @isolate, matcher: @matcher, negate: @negate, &block)
|
32
|
+
|
33
|
+
::Expresenter.call(passed?(test)).with(
|
34
|
+
actual: test.actual,
|
35
|
+
error: test.error,
|
36
|
+
expected: @matcher.expected,
|
37
|
+
got: test.got,
|
38
|
+
level: self.class.level,
|
39
|
+
matcher: @matcher.class.to_sym,
|
40
|
+
negate: @negate
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# :nocov:
|
45
|
+
|
46
|
+
# A string containing a human-readable representation of the definition.
|
47
|
+
#
|
48
|
+
# @example The human-readable representation of an absolute requirement.
|
49
|
+
# require "spectus"
|
50
|
+
# require "matchi/helper"
|
51
|
+
#
|
52
|
+
# include Matchi::Helper
|
53
|
+
#
|
54
|
+
# definition = Spectus.must equal 1
|
55
|
+
# definition.inspect
|
56
|
+
# # => #<MUST Matchi::Matcher::Equal(1) isolate=false negate=false>
|
57
|
+
#
|
58
|
+
# @return [String] The human-readable representation of the definition.
|
59
|
+
#
|
60
|
+
# @api public
|
61
|
+
def inspect
|
62
|
+
"#<#{self.class.level} #{@matcher.inspect} isolate=#{@isolate} negate=#{@negate}>"
|
63
|
+
end
|
64
|
+
|
65
|
+
# :nocov:
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Code experiment result.
|
70
|
+
#
|
71
|
+
# @param test [::TestTube::Base] The state of the experiment.
|
72
|
+
#
|
73
|
+
# @see https://github.com/fixrb/test_tube
|
74
|
+
#
|
75
|
+
# @return [Boolean] The result of the test (passed or failed).
|
76
|
+
def passed?(test)
|
77
|
+
test.got.equal?(true)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Spectus
|
6
|
+
module Requirement
|
7
|
+
# Optional requirement level.
|
8
|
+
class Optional < Base
|
9
|
+
# Key word for use in RFCs to indicate requirement levels.
|
10
|
+
#
|
11
|
+
# @return [Symbol] The requirement level.
|
12
|
+
def self.level
|
13
|
+
:MAY
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Code experiment result.
|
19
|
+
#
|
20
|
+
# @param (see Base#passed?)
|
21
|
+
#
|
22
|
+
# @return (see Base#passed?)
|
23
|
+
def passed?(test)
|
24
|
+
super || test.error.is_a?(::NoMethodError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Spectus
|
6
|
+
module Requirement
|
7
|
+
# Recommended and not recommended requirement levels.
|
8
|
+
class Recommended < Base
|
9
|
+
# Key word for use in RFCs to indicate requirement levels.
|
10
|
+
#
|
11
|
+
# @return [Symbol] The requirement level.
|
12
|
+
def self.level
|
13
|
+
:SHOULD
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Code experiment result.
|
19
|
+
#
|
20
|
+
# @param (see Base#passed?)
|
21
|
+
#
|
22
|
+
# @return (see Base#passed?)
|
23
|
+
def passed?(test)
|
24
|
+
super || test.error.nil?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module Spectus
|
6
|
+
module Requirement
|
7
|
+
# Absolute requirement and absolute prohibition levels.
|
8
|
+
class Required < Base
|
9
|
+
# Key word for use in RFCs to indicate requirement levels.
|
10
|
+
#
|
11
|
+
# @return [Symbol] The requirement level.
|
12
|
+
def self.level
|
13
|
+
:MUST
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
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:
|
4
|
+
version: 4.0.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-
|
11
|
+
date: 2021-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: expresenter
|
@@ -25,35 +25,35 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.3.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: test_tube
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.0.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: 2.
|
40
|
+
version: 2.0.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: brutal
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
48
|
-
type: :
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
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: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: matchi
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -187,14 +187,11 @@ files:
|
|
187
187
|
- LICENSE.md
|
188
188
|
- README.md
|
189
189
|
- lib/spectus.rb
|
190
|
-
- lib/spectus/
|
191
|
-
- lib/spectus/
|
192
|
-
- lib/spectus/
|
193
|
-
- lib/spectus/
|
194
|
-
- lib/spectus/
|
195
|
-
- lib/spectus/result.rb
|
196
|
-
- lib/spectus/result/fail.rb
|
197
|
-
- lib/spectus/result/pass.rb
|
190
|
+
- lib/spectus/requirement.rb
|
191
|
+
- lib/spectus/requirement/base.rb
|
192
|
+
- lib/spectus/requirement/optional.rb
|
193
|
+
- lib/spectus/requirement/recommended.rb
|
194
|
+
- lib/spectus/requirement/required.rb
|
198
195
|
homepage: https://github.com/fixrb/spectus
|
199
196
|
licenses:
|
200
197
|
- MIT
|
@@ -1,202 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
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
|
-
|
7
|
-
module Spectus
|
8
|
-
# Wraps the target of an expectation.
|
9
|
-
#
|
10
|
-
# @example
|
11
|
-
# it { actual value } # => ExpectationTarget wrapping the block
|
12
|
-
class ExpectationTarget
|
13
|
-
# Create a new expectation target
|
14
|
-
#
|
15
|
-
# @param callable [Proc] The object to test.
|
16
|
-
def initialize(&callable)
|
17
|
-
@callable = callable
|
18
|
-
end
|
19
|
-
|
20
|
-
# rubocop:disable Naming/MethodName
|
21
|
-
|
22
|
-
# This word, or the terms "REQUIRED" or "SHALL", mean that the
|
23
|
-
# definition is an absolute requirement of the specification.
|
24
|
-
#
|
25
|
-
# @example _Absolute requirement_ definition
|
26
|
-
# it { "foo".upcase }.MUST eql 'FOO'
|
27
|
-
#
|
28
|
-
# @param matcher [#matches?] The matcher.
|
29
|
-
#
|
30
|
-
# @return [Spectus::Result::Fail, Spectus::Result::Pass] Report if the spec
|
31
|
-
# pass or fail.
|
32
|
-
def MUST(matcher)
|
33
|
-
RequirementLevel::Must.new(
|
34
|
-
callable: callable,
|
35
|
-
isolation: false,
|
36
|
-
negate: false,
|
37
|
-
matcher: matcher
|
38
|
-
).call
|
39
|
-
end
|
40
|
-
|
41
|
-
# @example _Absolute requirement_ definition with isolation
|
42
|
-
# it { "foo".upcase }.MUST! eql 'FOO'
|
43
|
-
#
|
44
|
-
# @see MUST
|
45
|
-
def MUST!(matcher)
|
46
|
-
RequirementLevel::Must.new(
|
47
|
-
callable: callable,
|
48
|
-
isolation: true,
|
49
|
-
negate: false,
|
50
|
-
matcher: matcher
|
51
|
-
).call
|
52
|
-
end
|
53
|
-
|
54
|
-
# This phrase, or the phrase "SHALL NOT", mean that the
|
55
|
-
# definition is an absolute prohibition of the specification.
|
56
|
-
#
|
57
|
-
# @example _Absolute prohibition_ definition
|
58
|
-
# it { "foo".size }.MUST_NOT equal 42
|
59
|
-
#
|
60
|
-
# @param matcher [#matches?] The matcher.
|
61
|
-
#
|
62
|
-
# @return [Spectus::Result::Fail, Spectus::Result::Pass] Report if the spec
|
63
|
-
# pass or fail.
|
64
|
-
def MUST_NOT(matcher)
|
65
|
-
RequirementLevel::Must.new(
|
66
|
-
callable: callable,
|
67
|
-
isolation: false,
|
68
|
-
negate: true,
|
69
|
-
matcher: matcher
|
70
|
-
).call
|
71
|
-
end
|
72
|
-
|
73
|
-
# @example _Absolute prohibition_ definition with isolation
|
74
|
-
# it { "foo".size }.MUST_NOT! equal 42
|
75
|
-
#
|
76
|
-
# @see MUST_NOT
|
77
|
-
def MUST_NOT!(matcher)
|
78
|
-
RequirementLevel::Must.new(
|
79
|
-
callable: callable,
|
80
|
-
isolation: true,
|
81
|
-
negate: true,
|
82
|
-
matcher: matcher
|
83
|
-
).call
|
84
|
-
end
|
85
|
-
|
86
|
-
# This word, or the adjective "RECOMMENDED", mean that there
|
87
|
-
# may exist valid reasons in particular circumstances to ignore a
|
88
|
-
# particular item, but the full implications must be understood and
|
89
|
-
# carefully weighed before choosing a different course.
|
90
|
-
#
|
91
|
-
# @example _Recommended_ definition
|
92
|
-
# it { "foo".valid_encoding? }.SHOULD equal true
|
93
|
-
#
|
94
|
-
# @param matcher [#matches?] The matcher.
|
95
|
-
#
|
96
|
-
# @return [Spectus::Result::Fail, Spectus::Result::Pass] Report if the spec
|
97
|
-
# pass or fail.
|
98
|
-
def SHOULD(matcher)
|
99
|
-
RequirementLevel::Should.new(
|
100
|
-
callable: callable,
|
101
|
-
isolation: false,
|
102
|
-
negate: false,
|
103
|
-
matcher: matcher
|
104
|
-
).call
|
105
|
-
end
|
106
|
-
|
107
|
-
# @example _Recommended_ definition with isolation
|
108
|
-
# it { "foo".valid_encoding? }.SHOULD! equal true
|
109
|
-
#
|
110
|
-
# @see SHOULD
|
111
|
-
def SHOULD!(matcher)
|
112
|
-
RequirementLevel::Should.new(
|
113
|
-
callable: callable,
|
114
|
-
isolation: true,
|
115
|
-
negate: false,
|
116
|
-
matcher: matcher
|
117
|
-
).call
|
118
|
-
end
|
119
|
-
|
120
|
-
# This phrase, or the phrase "NOT RECOMMENDED" mean that
|
121
|
-
# there may exist valid reasons in particular circumstances when the
|
122
|
-
# particular behavior is acceptable or even useful, but the full
|
123
|
-
# implications should be understood and the case carefully weighed
|
124
|
-
# before implementing any behavior described with this label.
|
125
|
-
#
|
126
|
-
# @example _Not recommended_ definition
|
127
|
-
# it { "".blank? }.SHOULD_NOT raise_exception NoMethodError
|
128
|
-
#
|
129
|
-
# @param matcher [#matches?] The matcher.
|
130
|
-
#
|
131
|
-
# @return [Spectus::Result::Fail, Spectus::Result::Pass] Report if the spec
|
132
|
-
# pass or fail.
|
133
|
-
def SHOULD_NOT(matcher)
|
134
|
-
RequirementLevel::Should.new(
|
135
|
-
callable: callable,
|
136
|
-
isolation: false,
|
137
|
-
negate: true,
|
138
|
-
matcher: matcher
|
139
|
-
).call
|
140
|
-
end
|
141
|
-
|
142
|
-
# @example _Not recommended_ definition with isolation
|
143
|
-
# it { "".blank? }.SHOULD_NOT! raise_exception NoMethodError
|
144
|
-
#
|
145
|
-
# @see SHOULD_NOT
|
146
|
-
def SHOULD_NOT!(matcher)
|
147
|
-
RequirementLevel::Should.new(
|
148
|
-
callable: callable,
|
149
|
-
isolation: true,
|
150
|
-
negate: true,
|
151
|
-
matcher: matcher
|
152
|
-
).call
|
153
|
-
end
|
154
|
-
|
155
|
-
# This word, or the adjective "OPTIONAL", mean that an item is
|
156
|
-
# truly optional. One vendor may choose to include the item because a
|
157
|
-
# particular marketplace requires it or because the vendor feels that
|
158
|
-
# it enhances the product while another vendor may omit the same item.
|
159
|
-
# An implementation which does not include a particular option MUST be
|
160
|
-
# prepared to interoperate with another implementation which does
|
161
|
-
# include the option, though perhaps with reduced functionality. In the
|
162
|
-
# same vein an implementation which does include a particular option
|
163
|
-
# MUST be prepared to interoperate with another implementation which
|
164
|
-
# does not include the option (except, of course, for the feature the
|
165
|
-
# option provides.)
|
166
|
-
#
|
167
|
-
# @example _Optional_ definition
|
168
|
-
# it { "foo".bar }.MAY match /^foo$/
|
169
|
-
#
|
170
|
-
# @param matcher [#matches?] The matcher.
|
171
|
-
#
|
172
|
-
# @return [Spectus::Result::Fail, Spectus::Result::Pass] Report if the spec pass or fail.
|
173
|
-
def MAY(matcher)
|
174
|
-
RequirementLevel::May.new(
|
175
|
-
callable: callable,
|
176
|
-
isolation: false,
|
177
|
-
negate: false,
|
178
|
-
matcher: matcher
|
179
|
-
).call
|
180
|
-
end
|
181
|
-
|
182
|
-
# @example _Optional_ definition with isolation
|
183
|
-
# it { "foo".bar }.MAY! match /^foo$/
|
184
|
-
#
|
185
|
-
# @see MAY
|
186
|
-
def MAY!(matcher)
|
187
|
-
RequirementLevel::May.new(
|
188
|
-
callable: callable,
|
189
|
-
isolation: true,
|
190
|
-
negate: false,
|
191
|
-
matcher: matcher
|
192
|
-
).call
|
193
|
-
end
|
194
|
-
|
195
|
-
# rubocop:enable Naming/MethodName
|
196
|
-
|
197
|
-
protected
|
198
|
-
|
199
|
-
# @return [#call] The callable object to test.
|
200
|
-
attr_reader :callable
|
201
|
-
end
|
202
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "test_tube"
|
4
|
-
|
5
|
-
require_relative File.join("..", "result")
|
6
|
-
|
7
|
-
module Spectus
|
8
|
-
# Namespace for the requirement levels.
|
9
|
-
module RequirementLevel
|
10
|
-
# Requirement level's base class.
|
11
|
-
class Base
|
12
|
-
# Initialize the requirement level class.
|
13
|
-
#
|
14
|
-
# @param callable [#call] The callable object to test.
|
15
|
-
# @param isolation [Boolean] Compute actual in isolation?
|
16
|
-
# @param negate [Boolean] Invert the matcher or not.
|
17
|
-
# @param matcher [#matches?] The matcher.
|
18
|
-
def initialize(callable:, isolation:, matcher:, negate:)
|
19
|
-
@negate = negate
|
20
|
-
@matcher = matcher
|
21
|
-
@experiment = ::TestTube.invoke(
|
22
|
-
callable,
|
23
|
-
isolation: isolation,
|
24
|
-
matcher: matcher,
|
25
|
-
negate: negate
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
# @return [TestTube::Base] The experiment.
|
30
|
-
attr_reader :experiment
|
31
|
-
|
32
|
-
# @return [#matches?] The matcher that performed a boolean comparison
|
33
|
-
# between the actual value and the expected value.
|
34
|
-
attr_reader :matcher
|
35
|
-
|
36
|
-
# The result of the expectation.
|
37
|
-
#
|
38
|
-
# @raise [Spectus::Result::Fail] The expectation failed.
|
39
|
-
# @return [Spectus::Result::Pass] The expectation passed.
|
40
|
-
def call
|
41
|
-
Result.call(pass?).with(
|
42
|
-
actual: experiment.actual,
|
43
|
-
error: experiment.error,
|
44
|
-
expected: matcher.expected,
|
45
|
-
got: experiment.got,
|
46
|
-
level: level,
|
47
|
-
matcher: matcher.class.to_sym,
|
48
|
-
negate: negate?
|
49
|
-
)
|
50
|
-
end
|
51
|
-
|
52
|
-
protected
|
53
|
-
|
54
|
-
# Some key words for use in RFCs to indicate requirement levels.
|
55
|
-
#
|
56
|
-
# @return [:MUST, :SHOULD, :MAY] The requirement level.
|
57
|
-
def level
|
58
|
-
self.class.name.split("::").fetch(-1).upcase.to_sym
|
59
|
-
end
|
60
|
-
|
61
|
-
# @note The boolean comparison between the actual value and the expected
|
62
|
-
# value can be evaluated to a negative assertion.
|
63
|
-
#
|
64
|
-
# @return [Boolean] Invert the matcher or not.
|
65
|
-
def negate?
|
66
|
-
@negate
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "must"
|
4
|
-
|
5
|
-
module Spectus
|
6
|
-
module RequirementLevel
|
7
|
-
# May requirement level's class.
|
8
|
-
class May < Must
|
9
|
-
# Evaluate the expectation.
|
10
|
-
#
|
11
|
-
# @return [Boolean] Report if the low expectation pass or fail?
|
12
|
-
def pass?
|
13
|
-
super || experiment.error.is_a?(::NoMethodError)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "base"
|
4
|
-
|
5
|
-
module Spectus
|
6
|
-
module RequirementLevel
|
7
|
-
# Must requirement level's class.
|
8
|
-
class Must < Base
|
9
|
-
# Evaluate the expectation.
|
10
|
-
#
|
11
|
-
# @return [Boolean] Report if the high expectation pass or fail?
|
12
|
-
def pass?
|
13
|
-
experiment.got.equal?(true)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "must"
|
4
|
-
|
5
|
-
module Spectus
|
6
|
-
module RequirementLevel
|
7
|
-
# Should requirement level's class.
|
8
|
-
class Should < Must
|
9
|
-
# Evaluate the expectation.
|
10
|
-
#
|
11
|
-
# @return [Boolean] Report if the medium expectation pass or fail?
|
12
|
-
def pass?
|
13
|
-
super || experiment.error.nil?
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/spectus/result.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative File.join("result", "fail")
|
4
|
-
require_relative File.join("result", "pass")
|
5
|
-
|
6
|
-
module Spectus
|
7
|
-
# Namespace for the results.
|
8
|
-
module Result
|
9
|
-
# @param is_passed [Boolean] The value of an assertion.
|
10
|
-
# @return [Class<Spectus::Result::Pass>, Class<Spectus::Result::Fail>] The
|
11
|
-
# class of the result.
|
12
|
-
# @example Get the pass class result.
|
13
|
-
# call(true) # => Pass
|
14
|
-
def self.call(is_passed)
|
15
|
-
is_passed ? Pass : Fail
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/spectus/result/fail.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "expresenter/fail"
|
4
|
-
|
5
|
-
module Spectus
|
6
|
-
module Result
|
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
|
10
|
-
class Fail < ::Expresenter::Fail
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/lib/spectus/result/pass.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "expresenter/pass"
|
4
|
-
|
5
|
-
module Spectus
|
6
|
-
module Result
|
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
|
10
|
-
class Pass < ::Expresenter::Pass
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|