spectus 3.0.10 → 3.1.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 +66 -77
- data/lib/spectus.rb +2 -4
- data/lib/spectus/exam.rb +56 -0
- data/lib/spectus/expectation_target.rb +87 -70
- data/lib/spectus/requirement_level/base.rb +48 -73
- data/lib/spectus/requirement_level/may.rb +17 -0
- data/lib/spectus/requirement_level/must.rb +17 -0
- data/lib/spectus/requirement_level/should.rb +17 -0
- data/lib/spectus/result/common.rb +174 -0
- data/lib/spectus/result/fail.rb +40 -17
- data/lib/spectus/result/pass.rb +48 -21
- metadata +22 -24
- data/lib/spectus/matchers.rb +0 -33
- data/lib/spectus/report.rb +0 -92
- data/lib/spectus/requirement_level/high.rb +0 -27
- data/lib/spectus/requirement_level/low.rb +0 -27
- data/lib/spectus/requirement_level/medium.rb +0 -27
- data/lib/spectus/result/base.rb +0 -112
- data/lib/spectus/sandbox.rb +0 -61
@@ -1,109 +1,84 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'aw'
|
4
|
-
|
5
3
|
module Spectus
|
6
4
|
# Namespace for the requirement levels.
|
7
|
-
#
|
8
|
-
# @api private
|
9
|
-
#
|
10
5
|
module RequirementLevel
|
11
6
|
# Requirement level's base class.
|
12
|
-
#
|
13
7
|
class Base
|
14
8
|
# Initialize the requirement level class.
|
15
9
|
#
|
16
|
-
# @param
|
17
|
-
# @param
|
18
|
-
# @param
|
19
|
-
# @param
|
20
|
-
def initialize(
|
21
|
-
@
|
22
|
-
@
|
23
|
-
|
24
|
-
@
|
10
|
+
# @param callable [#call] The callable object to test.
|
11
|
+
# @param isolation [Boolean] Compute actual in isolation?
|
12
|
+
# @param negate [Boolean] Positive or negative assertion?
|
13
|
+
# @param matcher [#matches?] The matcher.
|
14
|
+
def initialize(callable:, isolation:, negate:, matcher:)
|
15
|
+
@negate = negate
|
16
|
+
@matcher = matcher
|
17
|
+
|
18
|
+
@exam = Exam.new(
|
19
|
+
callable: callable,
|
20
|
+
isolation: isolation,
|
21
|
+
negate: negate,
|
22
|
+
matcher: matcher
|
23
|
+
)
|
25
24
|
end
|
26
25
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
26
|
+
# @return [#Exam] The exam.
|
27
|
+
attr_reader :exam
|
28
|
+
|
29
|
+
# @return [#matches?] The matcher that performed a boolean comparison
|
30
|
+
# between the actual value and the expected value.
|
30
31
|
attr_reader :matcher
|
31
32
|
|
32
|
-
# The
|
33
|
+
# The result of the expectation.
|
33
34
|
#
|
34
|
-
# @return [
|
35
|
-
def
|
36
|
-
|
35
|
+
# @return [Result::Fail, Result::Pass] The test result.
|
36
|
+
def call
|
37
|
+
pass? ? pass! : fail!
|
37
38
|
end
|
38
39
|
|
39
|
-
# @!attribute [r] subject
|
40
|
-
#
|
41
|
-
# @return [#object_id] The front object to test.
|
42
|
-
attr_reader :subject
|
43
|
-
|
44
|
-
# @!attribute [r] challenges
|
45
|
-
#
|
46
|
-
# @return [Array] A list of challenges.
|
47
|
-
attr_reader :challenges
|
48
|
-
|
49
40
|
protected
|
50
41
|
|
51
|
-
# @
|
52
|
-
|
53
|
-
|
54
|
-
def pass!(state)
|
55
|
-
r = Report.new(matcher, negate?, state, true)
|
56
|
-
|
57
|
-
Result::Pass.new(r, *result_signature(state))
|
42
|
+
# @return [Result::Pass] A passed spec result.
|
43
|
+
def pass!
|
44
|
+
Result::Pass.new(**details)
|
58
45
|
end
|
59
46
|
|
60
|
-
# @
|
61
|
-
|
62
|
-
|
63
|
-
def fail!(state)
|
64
|
-
r = Report.new(matcher, negate?, state, false)
|
65
|
-
|
66
|
-
raise Result::Fail.new(r, *result_signature(state)), r, caller[2..-1]
|
47
|
+
# @raise [Result::Fail] A failed spec result.
|
48
|
+
def fail!
|
49
|
+
raise Result::Fail.new(**details)
|
67
50
|
end
|
68
51
|
|
69
|
-
# @
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
negate?,
|
82
|
-
state.valid?
|
83
|
-
]
|
52
|
+
# @return [Hash] List of parameters.
|
53
|
+
def details
|
54
|
+
{
|
55
|
+
actual: exam.actual,
|
56
|
+
error: exam.exception,
|
57
|
+
expected: matcher.expected,
|
58
|
+
got: exam.got,
|
59
|
+
negate: negate?,
|
60
|
+
valid: exam.valid?,
|
61
|
+
matcher: matcher.class.to_sym,
|
62
|
+
level: level
|
63
|
+
}
|
84
64
|
end
|
85
65
|
|
86
66
|
# @return [Symbol] The requirement level.
|
87
67
|
def level
|
88
|
-
self.class.name.split('::').
|
68
|
+
self.class.name.split('::').fetch(-1).upcase.to_sym
|
89
69
|
end
|
90
70
|
|
91
|
-
# @
|
71
|
+
# @note The boolean comparison between the actual value and the expected
|
72
|
+
# value can be evaluated to a negative assertion.
|
92
73
|
#
|
93
|
-
# @return [
|
94
|
-
def
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
# @return [Sandbox] The sandbox.
|
99
|
-
def execute
|
100
|
-
Sandbox.new(matcher, negate?, subject, *challenges)
|
74
|
+
# @return [Boolean] Positive or negative assertion?
|
75
|
+
def negate?
|
76
|
+
@negate
|
101
77
|
end
|
102
78
|
end
|
103
79
|
end
|
104
80
|
end
|
105
81
|
|
106
|
-
require_relative File.join('..', '
|
82
|
+
require_relative File.join('..', 'exam')
|
107
83
|
require_relative File.join('..', 'result', 'fail')
|
108
84
|
require_relative File.join('..', 'result', 'pass')
|
109
|
-
require_relative File.join('..', 'sandbox')
|
@@ -0,0 +1,17 @@
|
|
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 || exam.exception.is_a?(::NoMethodError)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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
|
+
exam.valid?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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 || exam.exception.nil?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spectus
|
4
|
+
# Namespace for the results.
|
5
|
+
module Result
|
6
|
+
# Common collection of methods for Result's classes.
|
7
|
+
module Common
|
8
|
+
# @return [#object_id] Returned value by the challenged subject.
|
9
|
+
attr_reader :actual
|
10
|
+
|
11
|
+
# @return [Exception, nil] Any possible raised exception.
|
12
|
+
attr_reader :error
|
13
|
+
|
14
|
+
# @return [#object_id] The expected value.
|
15
|
+
attr_reader :expected
|
16
|
+
|
17
|
+
# @return [#object_id] The result of the boolean comparison between the
|
18
|
+
# actual value and the expected value through the matcher.
|
19
|
+
attr_reader :got
|
20
|
+
|
21
|
+
# @return [#object_id] The matcher.
|
22
|
+
attr_reader :matcher
|
23
|
+
|
24
|
+
# @return [:MUST, :SHOULD, :MAY] The requirement level of the expectation.
|
25
|
+
attr_reader :level
|
26
|
+
|
27
|
+
# Common initialize method.
|
28
|
+
#
|
29
|
+
# @param actual [#object_id] Returned value by the challenged subject.
|
30
|
+
# @param error [Exception, nil] Any possible raised exception.
|
31
|
+
# @param expected [#object_id] The expected value.
|
32
|
+
# @param got [Boolean, nil] The result of the boolean comparison
|
33
|
+
# between the actual value and the expected value through the matcher.
|
34
|
+
# @param negate [Boolean] Evaluated to a negative assertion?
|
35
|
+
# @param valid [Boolean] Report if the test was true or false?
|
36
|
+
# @param matcher [Symbol] The matcher.
|
37
|
+
# @param level [:MUST, :SHOULD, :MAY] The requirement level.
|
38
|
+
def initialize(actual:, error:, expected:, got:, negate:, valid:,
|
39
|
+
matcher:, level:)
|
40
|
+
|
41
|
+
@actual = actual
|
42
|
+
@error = error
|
43
|
+
@expected = expected
|
44
|
+
@got = got
|
45
|
+
@negate = negate
|
46
|
+
@valid = valid
|
47
|
+
@matcher = matcher
|
48
|
+
@level = level
|
49
|
+
|
50
|
+
super(to_s) if failed?
|
51
|
+
end
|
52
|
+
|
53
|
+
# The value of the negate instance variable.
|
54
|
+
#
|
55
|
+
# @return [Boolean] Evaluated to a negative assertion?
|
56
|
+
def negate?
|
57
|
+
@negate
|
58
|
+
end
|
59
|
+
|
60
|
+
# The state of error.
|
61
|
+
#
|
62
|
+
# @return [Boolean] The test raised an error?
|
63
|
+
def error?
|
64
|
+
!error.nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
# The state of success.
|
68
|
+
#
|
69
|
+
# @return [Boolean] The test was a success?
|
70
|
+
def success?
|
71
|
+
got.equal?(true)
|
72
|
+
end
|
73
|
+
|
74
|
+
# The value of the boolean comparison between the actual value and the
|
75
|
+
# expected value.
|
76
|
+
#
|
77
|
+
# @return [Boolean] The test was true or false?
|
78
|
+
def valid?
|
79
|
+
@valid
|
80
|
+
end
|
81
|
+
|
82
|
+
# A string containing a human-readable representation of the result.
|
83
|
+
#
|
84
|
+
# @return [String] The human-readable representation of the result.
|
85
|
+
def inspect
|
86
|
+
"#{self.class}(actual: #{actual.inspect}, " \
|
87
|
+
"error: #{error.inspect}, " \
|
88
|
+
"expected: #{expected.inspect}, " \
|
89
|
+
"got: #{got.inspect}, " \
|
90
|
+
"matcher: #{matcher.inspect}, " \
|
91
|
+
"negate: #{negate?.inspect}, " \
|
92
|
+
"level: #{level.inspect}, " \
|
93
|
+
"valid: #{valid?.inspect})" \
|
94
|
+
end
|
95
|
+
|
96
|
+
# The readable definition.
|
97
|
+
#
|
98
|
+
# @return [String] A readable string of the definition.
|
99
|
+
def definition
|
100
|
+
[matcher, expected&.inspect].compact.join(' ')
|
101
|
+
end
|
102
|
+
|
103
|
+
# The negation, if any.
|
104
|
+
#
|
105
|
+
# @return [String] The negation, or an empty string.
|
106
|
+
def maybe_negate
|
107
|
+
negate? ? ' not' : ''
|
108
|
+
end
|
109
|
+
|
110
|
+
# The summary of the result.
|
111
|
+
#
|
112
|
+
# @return [String] A string representing the summary of the result.
|
113
|
+
def summary
|
114
|
+
if error?
|
115
|
+
error.message
|
116
|
+
elsif actual.is_a?(::Exception)
|
117
|
+
actual.message
|
118
|
+
elsif actual == expected
|
119
|
+
"expected#{maybe_negate} to #{definition}"
|
120
|
+
else
|
121
|
+
"expected #{actual.inspect}#{maybe_negate} to #{definition}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Express the result with one colored char.
|
126
|
+
#
|
127
|
+
# @return [String] The colored char that identify the result.
|
128
|
+
def colored_char
|
129
|
+
color(char)
|
130
|
+
end
|
131
|
+
|
132
|
+
# The colored string representation of the result.
|
133
|
+
#
|
134
|
+
# @return [String] A string representing the result.
|
135
|
+
def colored_string
|
136
|
+
color(to_s)
|
137
|
+
end
|
138
|
+
|
139
|
+
# The representation of the result.
|
140
|
+
#
|
141
|
+
# @return [String] A string representing the result.
|
142
|
+
def to_s
|
143
|
+
"#{titre}: #{summary}."
|
144
|
+
end
|
145
|
+
|
146
|
+
# Titre for the result.
|
147
|
+
#
|
148
|
+
# @return [String] A string representing the titre.
|
149
|
+
def titre
|
150
|
+
if error?
|
151
|
+
error.class.name
|
152
|
+
else
|
153
|
+
to_sym.to_s.capitalize
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
|
159
|
+
def color(str)
|
160
|
+
if success?
|
161
|
+
"\e[32m#{str}\e[0m"
|
162
|
+
elsif info?
|
163
|
+
"\e[36m#{str}\e[0m"
|
164
|
+
elsif warning?
|
165
|
+
"\e[33m#{str}\e[0m"
|
166
|
+
elsif failure?
|
167
|
+
"\e[35m#{str}\e[0m"
|
168
|
+
else
|
169
|
+
"\e[31m#{str}\e[0m"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
data/lib/spectus/result/fail.rb
CHANGED
@@ -1,32 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'common'
|
4
4
|
|
5
5
|
module Spectus
|
6
6
|
module Result
|
7
7
|
# The class that is responsible for reporting that the expectation is false.
|
8
8
|
class Fail < ::StandardError
|
9
|
-
include
|
9
|
+
include Common
|
10
10
|
|
11
|
-
#
|
11
|
+
# Did the test fail?
|
12
12
|
#
|
13
|
-
# @return [Boolean] The spec
|
14
|
-
def
|
15
|
-
|
13
|
+
# @return [Boolean] The spec passed or failed?
|
14
|
+
def failed?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
# Did the test pass?
|
19
|
+
#
|
20
|
+
# @return [Boolean] The spec passed or failed?
|
21
|
+
def passed?
|
22
|
+
!failed?
|
16
23
|
end
|
17
24
|
|
18
25
|
# The state of failure.
|
19
26
|
#
|
20
|
-
# @return [Boolean] The test was a failure
|
27
|
+
# @return [Boolean] The test was a failure?
|
21
28
|
def failure?
|
22
|
-
error
|
29
|
+
!error?
|
30
|
+
end
|
31
|
+
|
32
|
+
# The state of info.
|
33
|
+
#
|
34
|
+
# @return [Boolean] The test was an info?
|
35
|
+
def info?
|
36
|
+
false
|
23
37
|
end
|
24
38
|
|
25
|
-
# The state of
|
39
|
+
# The state of warning.
|
26
40
|
#
|
27
|
-
# @return [Boolean] The test was
|
28
|
-
def
|
29
|
-
|
41
|
+
# @return [Boolean] The test was a warning?
|
42
|
+
def warning?
|
43
|
+
false
|
30
44
|
end
|
31
45
|
|
32
46
|
# Identify the state of the result.
|
@@ -38,14 +52,23 @@ module Spectus
|
|
38
52
|
|
39
53
|
# Express the result with one char.
|
40
54
|
#
|
41
|
-
# @param color [Boolean] Enable the color.
|
42
|
-
#
|
43
55
|
# @return [String] The char that identify the result.
|
44
|
-
def
|
56
|
+
def char
|
57
|
+
if failure?
|
58
|
+
'F'
|
59
|
+
else
|
60
|
+
'E'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Express the result with one emoji.
|
65
|
+
#
|
66
|
+
# @return [String] The emoji that identify the result.
|
67
|
+
def emoji
|
45
68
|
if failure?
|
46
|
-
|
69
|
+
'❌'
|
47
70
|
else
|
48
|
-
|
71
|
+
'💥'
|
49
72
|
end
|
50
73
|
end
|
51
74
|
end
|