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