spectus 3.0.10 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 matcher [#matches?] The matcher.
17
- # @param negate [Boolean] Evaluate to a negative assertion.
18
- # @param subject [#object_id] The front object to test.
19
- # @param challenges [Array] A list of challenges.
20
- def initialize(matcher, negate, subject, *challenges)
21
- @matcher = matcher
22
- @negate = negate
23
- @subject = subject
24
- @challenges = challenges
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
- # @!attribute [r] matcher
28
- #
29
- # @return [#matches?] The matcher.
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 value of the negate instance variable.
33
+ # The result of the expectation.
33
34
  #
34
- # @return [Boolean] Evaluated to a negative assertion or not.
35
- def negate?
36
- @negate
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
- # @param state [Sandbox] The sandbox that tested the code.
52
- #
53
- # @return [Result::Pass] Pass the spec.
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
- # @param state [Sandbox] The sandbox that tested the code.
61
- #
62
- # @raise [Result::Fail] Fail the spec.
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
- # @param state [Sandbox] The sandbox that tested the code.
70
- #
71
- # @return [Array] List of parameters.
72
- def result_signature(state)
73
- [
74
- subject,
75
- state.last_challenge,
76
- state.actual,
77
- matcher,
78
- state.got,
79
- state.exception,
80
- level,
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('::').last.to_sym
68
+ self.class.name.split('::').fetch(-1).upcase.to_sym
89
69
  end
90
70
 
91
- # @param isolation [Boolean] Test in isolation.
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 [Sandbox] The sandbox.
94
- def sandbox(isolation)
95
- isolation ? ::Aw.fork! { execute } : execute
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('..', 'report')
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
@@ -1,32 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'base'
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 Base
9
+ include Common
10
10
 
11
- # The value of the expectation of the spec.
11
+ # Did the test fail?
12
12
  #
13
- # @return [Boolean] The spec was false.
14
- def result?
15
- false
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.nil?
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 error.
39
+ # The state of warning.
26
40
  #
27
- # @return [Boolean] The test was an error.
28
- def error?
29
- !failure?
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 to_char(color = false)
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
- color ? "\e[35mF\e[0m" : 'F'
69
+ ''
47
70
  else
48
- color ? "\e[31mE\e[0m" : 'E'
71
+ '💥'
49
72
  end
50
73
  end
51
74
  end