expresenter 1.5.0 → 1.5.1
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/LICENSE.md +1 -1
- data/README.md +113 -111
- data/lib/expresenter/common.rb +110 -30
- data/lib/expresenter/fail.rb +102 -30
- data/lib/expresenter/pass.rb +94 -32
- data/lib/expresenter.rb +49 -6
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6701ed87c0d50891bb8804abc202aa3a2579d34f658b2d8b59f2b7caec76228a
|
4
|
+
data.tar.gz: f9d618cddd0aeacb36667da36816a759ff768aadb3e0f401f893baecf1306a2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: edbc7c35fe288a72bf3160810a5acf87675785e49f6f508ceb60a146ad74aa6072a2a287c24cde38a20ed22db242c7f1f2aeb6202e25f7cbaeacd1f5d39e622c
|
7
|
+
data.tar.gz: 2f16a23515e63fa17773da941ecb099a45c04a9973bcc5224d39ba36b41aff28f49d9e148960101bb49b8f0fca52b34c03c17848795bfb2f9ae4500d42c61d4b
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -2,20 +2,27 @@
|
|
2
2
|
|
3
3
|
[](https://github.com/fixrb/expresenter/tags)
|
4
4
|
[](https://rubydoc.info/github/fixrb/expresenter/main)
|
5
|
-
[](https://github.com/fixrb/expresenter/actions?query=workflow%3Aruby+branch%3Amain)
|
6
|
-
[](https://github.com/fixrb/expresenter/actions?query=workflow%3Arubocop+branch%3Amain)
|
7
5
|
[](https://github.com/fixrb/expresenter/raw/main/LICENSE.md)
|
8
6
|
|
9
7
|
> A Ruby gem for presenting test expectation results with rich formatting and requirement level support. Perfect for test frameworks and assertion libraries that need flexible result reporting with support for MUST/SHOULD/MAY requirement levels.
|
10
8
|
|
11
9
|
## Features
|
12
10
|
|
13
|
-
- Rich result
|
14
|
-
-
|
15
|
-
-
|
16
|
-
- Emoji support for visual
|
17
|
-
-
|
18
|
-
-
|
11
|
+
- Rich test result presentation with:
|
12
|
+
- Colored output for different result types (success, warning, info, failure, error)
|
13
|
+
- Single-character indicators for compact output (".", "W", "I", "F", "E")
|
14
|
+
- Emoji support for visual feedback (✅, ⚠️, 💡, ❌, 💥)
|
15
|
+
- ANSI-colored formatted messages with bold titles
|
16
|
+
- Support for RFC 2119 requirement levels (MUST/SHOULD/MAY)
|
17
|
+
- Comprehensive result classification:
|
18
|
+
- Success: Test passed as expected (green)
|
19
|
+
- Warning: Non-critical issues, typically for SHOULD/MAY requirements (yellow)
|
20
|
+
- Info: Additional information about passing tests (blue)
|
21
|
+
- Failure: Test failed but no exception occurred (purple)
|
22
|
+
- Error: Unexpected exceptions during test execution (red)
|
23
|
+
- Built-in support for negative assertions
|
24
|
+
- Detailed error reporting with captured exceptions
|
25
|
+
- Clean integration with test frameworks via simple API
|
19
26
|
|
20
27
|
## Installation
|
21
28
|
|
@@ -39,133 +46,128 @@ gem install expresenter
|
|
39
46
|
|
40
47
|
## Usage
|
41
48
|
|
42
|
-
|
43
|
-
qualifying it with `MUST`, `SHOULD` and `MAY`, we can draw up several scenarios:
|
44
|
-
|
45
|
-
| Requirement levels | **MUST** | **SHOULD** | **MAY** |
|
46
|
-
| ------------------------- | -------- | ---------- | ------- |
|
47
|
-
| Implemented & Matched | `true` | `true` | `true` |
|
48
|
-
| Implemented & Not matched | `false` | `true` | `false` |
|
49
|
-
| Implemented & Exception | `false` | `false` | `false` |
|
50
|
-
| Not implemented | `false` | `false` | `true` |
|
51
|
-
|
52
|
-
Then,
|
53
|
-
|
54
|
-
* for a `true` assertion, a `Expresenter::Pass` instance can be returned;
|
55
|
-
* for a `false` assertion, a `Expresenter::Fail` exception can be raised.
|
56
|
-
|
57
|
-
Both class share a same `Common` interface.
|
58
|
-
|
59
|
-
Passed expectations can be classified as:
|
60
|
-
|
61
|
-
* ✅ success
|
62
|
-
* ⚠️ warning
|
63
|
-
* 💡 info
|
64
|
-
|
65
|
-
Failed expectations can be classified as:
|
66
|
-
|
67
|
-
* ❌ failure
|
68
|
-
* 💥 error
|
69
|
-
|
70
|
-
### Instantiation
|
71
|
-
|
72
|
-
The following parameters are required to instantiate the result:
|
73
|
-
|
74
|
-
* `actual`: Returned value by the challenged subject.
|
75
|
-
* `definition`: A readable string of the matcher and any expected values.
|
76
|
-
* `error`: Any possible raised exception.
|
77
|
-
* `got`: The result of the boolean comparison between the actual value and the expected value through the matcher.
|
78
|
-
* `negate`: Evaluated to a negative assertion?
|
79
|
-
* `level`: The requirement level (`:MUST`, `:SHOULD` or `:MAY`).
|
80
|
-
|
81
|
-
#### Examples
|
82
|
-
|
83
|
-
A passed expectation:
|
49
|
+
### Basic Example
|
84
50
|
|
85
51
|
```ruby
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
result.
|
97
|
-
result.
|
98
|
-
result.
|
99
|
-
result.
|
100
|
-
result.
|
101
|
-
result.colored_char # => "\e[32m.\e[0m"
|
102
|
-
result.colored_string # => "\e[32m\e[1mSuccess\e[22m: expected \"FOO\" not to eq \"foo\".\e[0m"
|
103
|
-
result.message # => "Success: expected \"FOO\" not to eq \"foo\"."
|
104
|
-
result.to_s # => "Success: expected \"FOO\" not to eq \"foo\"."
|
105
|
-
result.titre # => "Success"
|
52
|
+
# Create a successful test result
|
53
|
+
result = Expresenter.call(true).new(
|
54
|
+
actual: "foo",
|
55
|
+
definition: 'eq "foo"',
|
56
|
+
error: nil,
|
57
|
+
got: true,
|
58
|
+
negate: false,
|
59
|
+
level: :MUST
|
60
|
+
)
|
61
|
+
|
62
|
+
result.passed? # => true
|
63
|
+
result.to_sym # => :success
|
64
|
+
result.char # => "."
|
65
|
+
result.emoji # => "✅"
|
66
|
+
result.to_s # => 'Success: expected "foo" to eq "foo".'
|
106
67
|
```
|
107
68
|
|
108
|
-
|
69
|
+
### Handling Different Result Types
|
109
70
|
|
110
71
|
```ruby
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
72
|
+
# Warning example (non-critical requirement)
|
73
|
+
warning = Expresenter.call(true).new(
|
74
|
+
actual: "foo",
|
75
|
+
definition: "be_optimized",
|
76
|
+
error: nil,
|
77
|
+
got: false, # triggers warning state
|
78
|
+
negate: false,
|
79
|
+
level: :SHOULD
|
80
|
+
)
|
81
|
+
|
82
|
+
warning.warning? # => true
|
83
|
+
warning.char # => "W"
|
84
|
+
warning.emoji # => "⚠️"
|
85
|
+
|
86
|
+
# Failure example with exception
|
87
|
+
begin
|
88
|
+
Expresenter.call(false).with(
|
89
|
+
actual: 42,
|
90
|
+
definition: "eq 43",
|
91
|
+
error: nil,
|
92
|
+
got: false,
|
93
|
+
negate: false,
|
94
|
+
level: :MUST
|
95
|
+
)
|
96
|
+
rescue Expresenter::Fail => e
|
97
|
+
e.failure? # => true
|
98
|
+
e.char # => "F"
|
99
|
+
e.emoji # => "❌"
|
100
|
+
e.to_s # => "Failure: expected 42 to eq 43."
|
101
|
+
end
|
131
102
|
```
|
132
103
|
|
133
|
-
###
|
104
|
+
### Using Requirement Levels
|
134
105
|
|
135
|
-
|
106
|
+
Expresenter supports RFC 2119 requirement levels:
|
136
107
|
|
137
|
-
|
108
|
+
- `:MUST` - Critical requirements that must be satisfied
|
109
|
+
- `:SHOULD` - Recommended requirements that should be satisfied when possible
|
110
|
+
- `:MAY` - Optional requirements that may be satisfied
|
138
111
|
|
139
112
|
```ruby
|
140
|
-
|
113
|
+
# SHOULD requirement with warning
|
114
|
+
result = Expresenter.call(true).new(
|
115
|
+
actual: response,
|
116
|
+
definition: "have_fast_response_time",
|
117
|
+
error: nil,
|
118
|
+
got: false,
|
119
|
+
negate: false,
|
120
|
+
level: :SHOULD
|
121
|
+
)
|
122
|
+
|
123
|
+
result.warning? # => true
|
141
124
|
```
|
142
125
|
|
143
|
-
|
126
|
+
### Working with Negative Assertions
|
144
127
|
|
145
128
|
```ruby
|
146
|
-
|
129
|
+
# Negative assertion example
|
130
|
+
result = Expresenter.call(true).new(
|
131
|
+
actual: "foo",
|
132
|
+
definition: 'eq "bar"',
|
133
|
+
error: nil,
|
134
|
+
got: true,
|
135
|
+
negate: true, # indicates negative assertion
|
136
|
+
level: :MUST
|
137
|
+
)
|
138
|
+
|
139
|
+
result.negate? # => true
|
140
|
+
result.to_s # => 'Success: expected "foo" not to eq "bar".'
|
147
141
|
```
|
148
142
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
> 2: from (irb):43:in `rescue in irb_binding'
|
153
|
-
> 1: from /Users/cyril/github/fixrb/expresenter/lib/expresenter/fail.rb:25:in `with'
|
154
|
-
> Expresenter::Fail (Exception: BOOM.)
|
143
|
+
## Integration
|
144
|
+
|
145
|
+
Expresenter can be easily integrated into test frameworks and assertion libraries. It provides a simple API for creating and handling test results with rich formatting and requirement levels.
|
155
146
|
|
156
|
-
|
147
|
+
Example integration with a test framework:
|
157
148
|
|
158
|
-
|
159
|
-
|
149
|
+
```ruby
|
150
|
+
def assert(actual, matcher, level: :MUST)
|
151
|
+
result = matcher.match(actual)
|
152
|
+
|
153
|
+
Expresenter.call(result.success?).with(
|
154
|
+
actual: actual,
|
155
|
+
definition: matcher.description,
|
156
|
+
error: result.error,
|
157
|
+
got: result.matched?,
|
158
|
+
negate: false,
|
159
|
+
level: level
|
160
|
+
)
|
161
|
+
end
|
162
|
+
```
|
160
163
|
|
161
|
-
##
|
164
|
+
## Development
|
162
165
|
|
163
|
-
|
164
|
-
* Bugs/issues: https://github.com/fixrb/expresenter/issues
|
166
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
165
167
|
|
166
|
-
##
|
168
|
+
## Contributing
|
167
169
|
|
168
|
-
|
170
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/fixrb/expresenter. This project is intended to be a safe, welcoming space for collaboration.
|
169
171
|
|
170
172
|
## License
|
171
173
|
|
data/lib/expresenter/common.rb
CHANGED
@@ -1,58 +1,126 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Expresenter
|
4
|
-
# Common collection of methods.
|
4
|
+
# Common collection of methods shared between Pass and Fail result classes.
|
5
|
+
#
|
6
|
+
# This module provides the core functionality for presenting test results, including:
|
7
|
+
# - Access to test result data (actual value, definition, error state)
|
8
|
+
# - Test state queries (passed?, error?, success?)
|
9
|
+
# - Result formatting and presentation (summary, colored output)
|
10
|
+
# - Support for requirement levels (MUST/SHOULD/MAY)
|
11
|
+
#
|
12
|
+
# @example Using common methods in a test result
|
13
|
+
# result = Expresenter.call(true).new(
|
14
|
+
# actual: "foo",
|
15
|
+
# definition: 'eq "foo"',
|
16
|
+
# error: nil,
|
17
|
+
# got: true,
|
18
|
+
# negate: false,
|
19
|
+
# level: :MUST
|
20
|
+
# )
|
21
|
+
#
|
22
|
+
# result.passed? # => true
|
23
|
+
# result.success? # => true
|
24
|
+
# result.summary # => 'expected "foo" to eq "foo"'
|
25
|
+
# result.to_s # => 'Success: expected "foo" to eq "foo".'
|
26
|
+
#
|
5
27
|
module Common
|
6
|
-
#
|
28
|
+
# String constant used for joining message parts.
|
29
|
+
#
|
30
|
+
# @api private
|
7
31
|
SPACE = " "
|
8
32
|
|
9
|
-
#
|
33
|
+
# The actual value returned by the test subject.
|
34
|
+
#
|
35
|
+
# @return [#object_id] The value being tested against the expectation.
|
36
|
+
# @example
|
37
|
+
# result.actual # => "foo"
|
10
38
|
attr_reader :actual
|
11
39
|
|
12
|
-
#
|
40
|
+
# The human-readable description of the expectation.
|
41
|
+
#
|
42
|
+
# @return [String] Description combining the matcher and expected values.
|
43
|
+
# @example
|
44
|
+
# result.definition # => 'eq "foo"'
|
13
45
|
attr_reader :definition
|
14
46
|
|
15
|
-
#
|
47
|
+
# Any exception that was raised during the test.
|
48
|
+
#
|
49
|
+
# @return [Exception, nil] The error object if an exception occurred, nil otherwise.
|
50
|
+
# @example
|
51
|
+
# begin
|
52
|
+
# raise StandardError, "Oops"
|
53
|
+
# rescue => e
|
54
|
+
# result = Expresenter.call(false).new(error: e, ...)
|
55
|
+
# result.error # => #<StandardError: Oops>
|
56
|
+
# end
|
16
57
|
attr_reader :error
|
17
58
|
|
18
|
-
#
|
19
|
-
#
|
59
|
+
# The boolean result of comparing the actual value against the expectation.
|
60
|
+
#
|
61
|
+
# @return [#object_id] Usually true/false, but can be any object that responds to equal?
|
62
|
+
# @example
|
63
|
+
# result.got # => true
|
20
64
|
attr_reader :got
|
21
65
|
|
22
|
-
#
|
66
|
+
# The requirement level of the expectation.
|
67
|
+
#
|
68
|
+
# @return [:MUST, :SHOULD, :MAY] The RFC 2119 requirement level.
|
69
|
+
# @see https://www.ietf.org/rfc/rfc2119.txt
|
70
|
+
# @example
|
71
|
+
# result.level # => :MUST
|
23
72
|
attr_reader :level
|
24
73
|
|
25
|
-
#
|
74
|
+
# Checks if the test passed.
|
26
75
|
#
|
27
|
-
# @return [Boolean]
|
76
|
+
# @return [Boolean] true if the test passed, false otherwise.
|
77
|
+
# @example
|
78
|
+
# result.passed? # => true
|
28
79
|
def passed?
|
29
80
|
!failed?
|
30
81
|
end
|
31
82
|
|
32
|
-
#
|
83
|
+
# Checks if this is a negative assertion.
|
33
84
|
#
|
34
|
-
# @return [Boolean]
|
85
|
+
# @return [Boolean] true if this is a negative assertion (using not), false otherwise.
|
86
|
+
# @example
|
87
|
+
# result = Expresenter.call(true).new(negate: true, ...)
|
88
|
+
# result.negate? # => true
|
35
89
|
def negate?
|
36
90
|
@negate
|
37
91
|
end
|
38
92
|
|
39
|
-
#
|
93
|
+
# Checks if an error occurred during the test.
|
40
94
|
#
|
41
|
-
# @return [Boolean]
|
95
|
+
# @return [Boolean] true if an error was captured, false otherwise.
|
96
|
+
# @example
|
97
|
+
# begin
|
98
|
+
# raise "Oops"
|
99
|
+
# rescue => e
|
100
|
+
# result = Expresenter.call(false).new(error: e, ...)
|
101
|
+
# result.error? # => true
|
102
|
+
# end
|
42
103
|
def error?
|
43
104
|
!error.nil?
|
44
105
|
end
|
45
106
|
|
46
|
-
#
|
107
|
+
# Checks if the test was successful.
|
47
108
|
#
|
48
|
-
# @return [Boolean]
|
109
|
+
# @return [Boolean] true if the got value equals true, false otherwise.
|
110
|
+
# @example
|
111
|
+
# result = Expresenter.call(true).new(got: true, ...)
|
112
|
+
# result.success? # => true
|
49
113
|
def success?
|
50
114
|
got.equal?(true)
|
51
115
|
end
|
52
116
|
|
53
|
-
#
|
117
|
+
# Generates a human-readable summary of the test result.
|
54
118
|
#
|
55
|
-
# @return [String] A
|
119
|
+
# @return [String] A description of what was expected vs what was received.
|
120
|
+
# @example With regular value
|
121
|
+
# result.summary # => 'expected "foo" to eq "bar"'
|
122
|
+
# @example With error
|
123
|
+
# result.summary # => "Unexpected error occurred"
|
56
124
|
def summary
|
57
125
|
if error?
|
58
126
|
error.message
|
@@ -63,30 +131,40 @@ module Expresenter
|
|
63
131
|
end
|
64
132
|
end
|
65
133
|
|
66
|
-
#
|
134
|
+
# Returns the result indicator with ANSI color codes.
|
67
135
|
#
|
68
|
-
# @return [String]
|
136
|
+
# @return [String] A colored single character indicating the result type.
|
137
|
+
# @example
|
138
|
+
# result.colored_char # => "\e[32m.\e[0m"
|
69
139
|
def colored_char
|
70
140
|
color(char)
|
71
141
|
end
|
72
142
|
|
73
|
-
#
|
143
|
+
# Returns the full result message with ANSI color codes.
|
74
144
|
#
|
75
|
-
# @return [String] A string
|
145
|
+
# @return [String] A colored string with the complete test result.
|
146
|
+
# @example
|
147
|
+
# result.colored_string # => "\e[32mSuccess: expected 1 to eq 1.\e[0m"
|
76
148
|
def colored_string
|
77
149
|
color(to_bold_s)
|
78
150
|
end
|
79
151
|
|
80
|
-
#
|
152
|
+
# Returns the complete result message.
|
81
153
|
#
|
82
|
-
# @return [String] A string
|
154
|
+
# @return [String] A string containing the result type and summary.
|
155
|
+
# @example
|
156
|
+
# result.to_s # => "Success: expected 1 to eq 1."
|
83
157
|
def to_s
|
84
158
|
"#{titre}: #{summary}."
|
85
159
|
end
|
86
160
|
|
87
|
-
#
|
161
|
+
# Returns the title for the result type.
|
88
162
|
#
|
89
|
-
# @return [String]
|
163
|
+
# @return [String] Either the error class name or capitalized result type.
|
164
|
+
# @example Normal result
|
165
|
+
# result.titre # => "Success"
|
166
|
+
# @example Error result
|
167
|
+
# result.titre # => "StandardError"
|
90
168
|
def titre
|
91
169
|
if error?
|
92
170
|
error.class.name
|
@@ -97,16 +175,18 @@ module Expresenter
|
|
97
175
|
|
98
176
|
protected
|
99
177
|
|
100
|
-
#
|
178
|
+
# Returns the negation word if this is a negative assertion.
|
101
179
|
#
|
102
|
-
# @return [String, nil]
|
180
|
+
# @return [String, nil] Returns "not" for negative assertions, nil otherwise.
|
181
|
+
# @api private
|
103
182
|
def negation
|
104
183
|
"not" if negate?
|
105
184
|
end
|
106
185
|
|
107
|
-
#
|
186
|
+
# Returns the result message with a bold title.
|
108
187
|
#
|
109
|
-
# @return [String]
|
188
|
+
# @return [String] The result message with ANSI codes for bold title.
|
189
|
+
# @api private
|
110
190
|
def to_bold_s
|
111
191
|
"\e[1m#{titre}\e[22m: #{summary}."
|
112
192
|
end
|
data/lib/expresenter/fail.rb
CHANGED
@@ -3,38 +3,105 @@
|
|
3
3
|
require_relative "common"
|
4
4
|
|
5
5
|
module Expresenter
|
6
|
-
#
|
6
|
+
# Class responsible for handling and reporting failed test expectations.
|
7
|
+
#
|
8
|
+
# The Fail class represents test failures and errors, inheriting from StandardError
|
9
|
+
# to support exception handling. It distinguishes between two types of failures:
|
10
|
+
# - Regular failures: When an assertion fails but no exception occurred
|
11
|
+
# - Errors: When an unexpected exception was raised during the test
|
12
|
+
#
|
13
|
+
# @example Handling a regular test failure
|
14
|
+
# begin
|
15
|
+
# Expresenter.call(false).with(
|
16
|
+
# actual: 42,
|
17
|
+
# definition: 'eq 43',
|
18
|
+
# error: nil,
|
19
|
+
# got: false,
|
20
|
+
# negate: false,
|
21
|
+
# level: :MUST
|
22
|
+
# )
|
23
|
+
# rescue Expresenter::Fail => e
|
24
|
+
# e.failure? # => true
|
25
|
+
# e.error? # => false
|
26
|
+
# e.to_sym # => :failure
|
27
|
+
# e.char # => "F"
|
28
|
+
# e.emoji # => "❌"
|
29
|
+
# e.to_s # => "Failure: expected 42 to eq 43."
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# @example Handling a test error
|
33
|
+
# begin
|
34
|
+
# error = StandardError.new("Unexpected error")
|
35
|
+
# Expresenter.call(false).with(
|
36
|
+
# actual: nil,
|
37
|
+
# definition: 'be_valid',
|
38
|
+
# error: error,
|
39
|
+
# got: false,
|
40
|
+
# negate: false,
|
41
|
+
# level: :MUST
|
42
|
+
# )
|
43
|
+
# rescue Expresenter::Fail => e
|
44
|
+
# e.failure? # => false
|
45
|
+
# e.error? # => true
|
46
|
+
# e.to_sym # => :error
|
47
|
+
# e.char # => "E"
|
48
|
+
# e.emoji # => "💥"
|
49
|
+
# e.to_s # => "StandardError: Unexpected error."
|
50
|
+
# end
|
7
51
|
class Fail < ::StandardError
|
8
|
-
#
|
52
|
+
# Single character indicator for test failures.
|
53
|
+
# @api private
|
9
54
|
FAILURE_CHAR = "F"
|
10
55
|
|
11
|
-
# Emoji
|
56
|
+
# Emoji indicator for test failures.
|
57
|
+
# @api private
|
12
58
|
FAILURE_EMOJI = "❌"
|
13
59
|
|
14
|
-
#
|
60
|
+
# Single character indicator for test errors.
|
61
|
+
# @api private
|
15
62
|
ERROR_CHAR = "E"
|
16
63
|
|
17
|
-
# Emoji
|
64
|
+
# Emoji indicator for test errors.
|
65
|
+
# @api private
|
18
66
|
ERROR_EMOJI = "💥"
|
19
67
|
|
20
68
|
include Common
|
21
69
|
|
22
|
-
#
|
23
|
-
#
|
70
|
+
# Creates and raises a new Fail instance with the given details.
|
71
|
+
#
|
72
|
+
# @param details [Hash] Test result details (see #initialize for parameters)
|
73
|
+
# @raise [Fail] Always raises a Fail exception with the provided details
|
74
|
+
# @example
|
75
|
+
# Expresenter::Fail.with(
|
76
|
+
# actual: 42,
|
77
|
+
# definition: 'eq 43',
|
78
|
+
# error: nil,
|
79
|
+
# got: false,
|
80
|
+
# negate: false,
|
81
|
+
# level: :MUST
|
82
|
+
# ) # raises Expresenter::Fail
|
24
83
|
def self.with(**details)
|
25
84
|
raise new(**details)
|
26
85
|
end
|
27
86
|
|
28
|
-
#
|
87
|
+
# Initializes a new Fail instance.
|
88
|
+
#
|
89
|
+
# @param actual [#object_id] The actual value returned by the test
|
90
|
+
# @param definition [String] Human-readable description of the expectation
|
91
|
+
# @param error [Exception, nil] Any exception that was raised during the test
|
92
|
+
# @param got [Boolean, nil] Result of comparing actual vs expected values
|
93
|
+
# @param negate [Boolean] Whether this is a negative assertion
|
94
|
+
# @param level [:MUST, :SHOULD, :MAY] The requirement level of the test
|
29
95
|
#
|
30
|
-
# @
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
96
|
+
# @example Creating a failure result
|
97
|
+
# Fail.new(
|
98
|
+
# actual: 42,
|
99
|
+
# definition: 'eq 43',
|
100
|
+
# error: nil,
|
101
|
+
# got: false,
|
102
|
+
# negate: false,
|
103
|
+
# level: :MUST
|
104
|
+
# )
|
38
105
|
def initialize(actual:, definition:, error:, got:, negate:, level:)
|
39
106
|
@actual = actual
|
40
107
|
@definition = definition
|
@@ -46,37 +113,37 @@ module Expresenter
|
|
46
113
|
super(to_s)
|
47
114
|
end
|
48
115
|
|
49
|
-
#
|
116
|
+
# Always returns true since this class represents failed tests.
|
50
117
|
#
|
51
|
-
# @return [
|
118
|
+
# @return [true] Always returns true
|
52
119
|
def failed?
|
53
120
|
true
|
54
121
|
end
|
55
122
|
|
56
|
-
#
|
123
|
+
# Indicates if this is a regular failure (not an error).
|
57
124
|
#
|
58
|
-
# @return [Boolean]
|
125
|
+
# @return [Boolean] true if no error was captured, false otherwise
|
59
126
|
def failure?
|
60
127
|
!error?
|
61
128
|
end
|
62
129
|
|
63
|
-
#
|
130
|
+
# Fail results are never informational.
|
64
131
|
#
|
65
|
-
# @return [
|
132
|
+
# @return [false] Always returns false
|
66
133
|
def info?
|
67
134
|
false
|
68
135
|
end
|
69
136
|
|
70
|
-
#
|
137
|
+
# Fail results are never warnings.
|
71
138
|
#
|
72
|
-
# @return [
|
139
|
+
# @return [false] Always returns false
|
73
140
|
def warning?
|
74
141
|
false
|
75
142
|
end
|
76
143
|
|
77
|
-
#
|
144
|
+
# Returns the symbolic representation of the failure type.
|
78
145
|
#
|
79
|
-
# @return [
|
146
|
+
# @return [:failure, :error] :failure for regular failures, :error when an exception occurred
|
80
147
|
def to_sym
|
81
148
|
if failure?
|
82
149
|
:failure
|
@@ -85,9 +152,9 @@ module Expresenter
|
|
85
152
|
end
|
86
153
|
end
|
87
154
|
|
88
|
-
#
|
155
|
+
# Returns a single character representing the failure type.
|
89
156
|
#
|
90
|
-
# @return [String]
|
157
|
+
# @return [String] "F" for failures, "E" for errors
|
91
158
|
def char
|
92
159
|
if failure?
|
93
160
|
FAILURE_CHAR
|
@@ -96,9 +163,9 @@ module Expresenter
|
|
96
163
|
end
|
97
164
|
end
|
98
165
|
|
99
|
-
#
|
166
|
+
# Returns an emoji representing the failure type.
|
100
167
|
#
|
101
|
-
# @return [String]
|
168
|
+
# @return [String] "❌" for failures, "💥" for errors
|
102
169
|
def emoji
|
103
170
|
if failure?
|
104
171
|
FAILURE_EMOJI
|
@@ -109,6 +176,11 @@ module Expresenter
|
|
109
176
|
|
110
177
|
protected
|
111
178
|
|
179
|
+
# Applies color formatting to the given string based on failure type.
|
180
|
+
#
|
181
|
+
# @param str [String] The string to colorize
|
182
|
+
# @return [String] ANSI-colored string (purple for failures, red for errors)
|
183
|
+
# @api private
|
112
184
|
def color(str)
|
113
185
|
if failure?
|
114
186
|
"\e[35m#{str}\e[0m" # purple
|
data/lib/expresenter/pass.rb
CHANGED
@@ -3,46 +3,103 @@
|
|
3
3
|
require_relative "common"
|
4
4
|
|
5
5
|
module Expresenter
|
6
|
-
#
|
6
|
+
# Class responsible for handling and reporting successful test expectations.
|
7
|
+
#
|
8
|
+
# The Pass class represents test results that didn't fail, but can be in different states:
|
9
|
+
# - Success: Test passed completely as expected
|
10
|
+
# - Warning: Test passed but with some concerns (typically for :SHOULD or :MAY requirements)
|
11
|
+
# - Info: Test passed but with additional information to note
|
12
|
+
#
|
13
|
+
# Each state has its own character indicator, emoji, and color for easy visual identification
|
14
|
+
# in test output:
|
15
|
+
# - Success: "." (green) ✅
|
16
|
+
# - Warning: "W" (yellow) ⚠️
|
17
|
+
# - Info: "I" (blue) 💡
|
18
|
+
#
|
19
|
+
# @example Creating a successful test result
|
20
|
+
# result = Expresenter::Pass.new(
|
21
|
+
# actual: "foo",
|
22
|
+
# definition: 'eq "foo"',
|
23
|
+
# error: nil,
|
24
|
+
# got: true,
|
25
|
+
# negate: false,
|
26
|
+
# level: :MUST
|
27
|
+
# )
|
28
|
+
# result.success? # => true
|
29
|
+
# result.warning? # => false
|
30
|
+
# result.info? # => false
|
31
|
+
# result.to_sym # => :success
|
32
|
+
# result.char # => "."
|
33
|
+
# result.emoji # => "✅"
|
34
|
+
# result.to_s # => "Success: expected \"foo\" to eq \"foo\"."
|
35
|
+
#
|
36
|
+
# @example Creating a warning result
|
37
|
+
# result = Expresenter::Pass.new(
|
38
|
+
# actual: "foo",
|
39
|
+
# definition: 'eq "foo"',
|
40
|
+
# error: nil,
|
41
|
+
# got: false, # Warning state is triggered when got: false
|
42
|
+
# negate: false,
|
43
|
+
# level: :SHOULD
|
44
|
+
# )
|
45
|
+
# result.warning? # => true
|
46
|
+
# result.to_sym # => :warning
|
47
|
+
# result.char # => "W"
|
48
|
+
# result.emoji # => "⚠️"
|
7
49
|
class Pass
|
8
|
-
#
|
50
|
+
# Single character indicator for informational results.
|
51
|
+
# @api private
|
9
52
|
INFO_CHAR = "I"
|
10
53
|
|
11
|
-
# Emoji
|
54
|
+
# Emoji indicator for informational results.
|
55
|
+
# @api private
|
12
56
|
INFO_EMOJI = "💡"
|
13
57
|
|
14
|
-
#
|
58
|
+
# Single character indicator for successful results.
|
59
|
+
# @api private
|
15
60
|
SUCCESS_CHAR = "."
|
16
61
|
|
17
|
-
# Emoji
|
62
|
+
# Emoji indicator for successful results.
|
63
|
+
# @api private
|
18
64
|
SUCCESS_EMOJI = "✅"
|
19
65
|
|
20
|
-
#
|
66
|
+
# Single character indicator for warning results.
|
67
|
+
# @api private
|
21
68
|
WARNING_CHAR = "W"
|
22
69
|
|
23
|
-
# Emoji
|
70
|
+
# Emoji indicator for warning results.
|
71
|
+
# @api private
|
24
72
|
WARNING_EMOJI = "⚠️"
|
25
73
|
|
26
74
|
include Common
|
27
75
|
|
28
|
-
#
|
29
|
-
#
|
76
|
+
# Creates a new Pass instance with the given details.
|
77
|
+
#
|
78
|
+
# @param details [Hash] Test result details (see #initialize for parameters)
|
79
|
+
# @return [Pass] A new Pass instance
|
80
|
+
# @example
|
81
|
+
# Expresenter::Pass.with(
|
82
|
+
# actual: "foo",
|
83
|
+
# definition: 'eq "foo"',
|
84
|
+
# error: nil,
|
85
|
+
# got: true,
|
86
|
+
# negate: false,
|
87
|
+
# level: :MUST
|
88
|
+
# )
|
30
89
|
def self.with(**details)
|
31
90
|
new(**details)
|
32
91
|
end
|
33
92
|
|
34
93
|
alias message to_s
|
35
94
|
|
36
|
-
#
|
95
|
+
# Initializes a new Pass instance.
|
37
96
|
#
|
38
|
-
# @param actual
|
39
|
-
# @param definition [String]
|
40
|
-
#
|
41
|
-
# @param
|
42
|
-
# @param
|
43
|
-
#
|
44
|
-
# @param negate [Boolean] Evaluated to a negative assertion?
|
45
|
-
# @param level [:MUST, :SHOULD, :MAY] The requirement level.
|
97
|
+
# @param actual [#object_id] The actual value returned by the test
|
98
|
+
# @param definition [String] Human-readable description of the expectation
|
99
|
+
# @param error [Exception, nil] Any exception that occurred (for info states)
|
100
|
+
# @param got [Boolean, nil] Result of comparing actual vs expected values
|
101
|
+
# @param negate [Boolean] Whether this is a negative assertion
|
102
|
+
# @param level [:MUST, :SHOULD, :MAY] The requirement level of the test
|
46
103
|
def initialize(actual:, definition:, error:, got:, negate:, level:)
|
47
104
|
@actual = actual
|
48
105
|
@definition = definition
|
@@ -52,37 +109,37 @@ module Expresenter
|
|
52
109
|
@level = level
|
53
110
|
end
|
54
111
|
|
55
|
-
#
|
112
|
+
# Always returns false since this class represents passed tests.
|
56
113
|
#
|
57
|
-
# @return [
|
114
|
+
# @return [false] Always returns false
|
58
115
|
def failed?
|
59
116
|
false
|
60
117
|
end
|
61
118
|
|
62
|
-
#
|
119
|
+
# Pass results are never failures.
|
63
120
|
#
|
64
|
-
# @return [
|
121
|
+
# @return [false] Always returns false
|
65
122
|
def failure?
|
66
123
|
false
|
67
124
|
end
|
68
125
|
|
69
|
-
#
|
126
|
+
# Indicates if this is an informational result.
|
70
127
|
#
|
71
|
-
# @return [Boolean]
|
128
|
+
# @return [Boolean] true if an error was captured but the test still passed
|
72
129
|
def info?
|
73
130
|
!error.nil?
|
74
131
|
end
|
75
132
|
|
76
|
-
#
|
133
|
+
# Indicates if this is a warning result.
|
77
134
|
#
|
78
|
-
# @return [Boolean]
|
135
|
+
# @return [Boolean] true if got equals false, indicating a non-critical issue
|
79
136
|
def warning?
|
80
137
|
got.equal?(false)
|
81
138
|
end
|
82
139
|
|
83
|
-
#
|
140
|
+
# Returns the symbolic representation of the result state.
|
84
141
|
#
|
85
|
-
# @return [
|
142
|
+
# @return [:success, :warning, :info] The type of pass result
|
86
143
|
def to_sym
|
87
144
|
if success?
|
88
145
|
:success
|
@@ -93,9 +150,9 @@ module Expresenter
|
|
93
150
|
end
|
94
151
|
end
|
95
152
|
|
96
|
-
#
|
153
|
+
# Returns a single character representing the result state.
|
97
154
|
#
|
98
|
-
# @return [String]
|
155
|
+
# @return [String] "." for success, "W" for warning, "I" for info
|
99
156
|
def char
|
100
157
|
if success?
|
101
158
|
SUCCESS_CHAR
|
@@ -106,9 +163,9 @@ module Expresenter
|
|
106
163
|
end
|
107
164
|
end
|
108
165
|
|
109
|
-
#
|
166
|
+
# Returns an emoji representing the result state.
|
110
167
|
#
|
111
|
-
# @return [String]
|
168
|
+
# @return [String] "✅" for success, "⚠️" for warning, "💡" for info
|
112
169
|
def emoji
|
113
170
|
if success?
|
114
171
|
SUCCESS_EMOJI
|
@@ -121,6 +178,11 @@ module Expresenter
|
|
121
178
|
|
122
179
|
protected
|
123
180
|
|
181
|
+
# Applies color formatting to the given string based on result state.
|
182
|
+
#
|
183
|
+
# @param str [String] The string to colorize
|
184
|
+
# @return [String] ANSI-colored string (green for success, yellow for warning, blue for info)
|
185
|
+
# @api private
|
124
186
|
def color(str)
|
125
187
|
if success?
|
126
188
|
"\e[32m#{str}\e[0m" # green
|
data/lib/expresenter.rb
CHANGED
@@ -2,15 +2,58 @@
|
|
2
2
|
|
3
3
|
# Namespace for the Expresenter library.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# The Expresenter library provides a flexible way to present test expectation results with rich
|
6
|
+
# formatting and requirement level support. It is designed to work with test frameworks and
|
7
|
+
# assertion libraries that need detailed result reporting.
|
8
|
+
#
|
9
|
+
# Each expectation result can be categorized as:
|
10
|
+
# - Success: The test passed as expected
|
11
|
+
# - Warning: A non-critical test failure (typically for :SHOULD or :MAY requirements)
|
12
|
+
# - Info: Additional information about the test
|
13
|
+
# - Failure: A critical test failure
|
14
|
+
# - Error: An unexpected error occurred during the test
|
15
|
+
#
|
16
|
+
# @example Creating a passing expectation result
|
17
|
+
# result = Expresenter.call(true).with(
|
18
|
+
# actual: "FOO",
|
19
|
+
# definition: 'eql "foo"',
|
20
|
+
# error: nil,
|
21
|
+
# got: true,
|
22
|
+
# negate: true,
|
23
|
+
# level: :MUST
|
24
|
+
# )
|
25
|
+
# result.passed? # => true
|
26
|
+
# result.to_s # => "Success: expected \"FOO\" not to eql \"foo\"."
|
27
|
+
#
|
28
|
+
# @example Creating a failing expectation result
|
29
|
+
# # This will raise an Expresenter::Fail exception
|
30
|
+
# Expresenter.call(false).with(
|
31
|
+
# actual: "foo",
|
32
|
+
# definition: "eq 42",
|
33
|
+
# error: Exception.new("Test failed"),
|
34
|
+
# got: false,
|
35
|
+
# negate: false,
|
36
|
+
# level: :MUST
|
37
|
+
# )
|
38
|
+
#
|
7
39
|
module Expresenter
|
8
|
-
#
|
40
|
+
# Factory method that returns the appropriate result class based on the assertion outcome.
|
41
|
+
#
|
42
|
+
# @param is_passed [Boolean] The value of the assertion. True indicates a passing test,
|
43
|
+
# false indicates a failing test.
|
44
|
+
#
|
45
|
+
# @return [Class<Pass>, Class<Fail>] Returns the Pass class for passing tests or
|
46
|
+
# the Fail class for failing tests. These classes can then be instantiated with
|
47
|
+
# detailed test information using #with.
|
48
|
+
#
|
49
|
+
# @example Getting a Pass class for a successful test
|
50
|
+
# result_class = Expresenter.call(true)
|
51
|
+
# result_class # => Expresenter::Pass
|
9
52
|
#
|
10
|
-
# @
|
53
|
+
# @example Getting a Fail class for a failed test
|
54
|
+
# result_class = Expresenter.call(false)
|
55
|
+
# result_class # => Expresenter::Fail
|
11
56
|
#
|
12
|
-
# @example Get the pass class result.
|
13
|
-
# call(true) # => Pass
|
14
57
|
def self.call(is_passed)
|
15
58
|
is_passed ? Pass : Fail
|
16
59
|
end
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: expresenter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
|
+
autorequire:
|
8
9
|
bindir: bin
|
9
10
|
cert_chain: []
|
10
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
11
12
|
dependencies: []
|
12
13
|
description: Expectation result presenter.
|
13
14
|
email: contact@cyril.email
|
@@ -26,6 +27,7 @@ licenses:
|
|
26
27
|
- MIT
|
27
28
|
metadata:
|
28
29
|
rubygems_mfa_required: 'true'
|
30
|
+
post_install_message:
|
29
31
|
rdoc_options: []
|
30
32
|
require_paths:
|
31
33
|
- lib
|
@@ -33,14 +35,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
33
35
|
requirements:
|
34
36
|
- - ">="
|
35
37
|
- !ruby/object:Gem::Version
|
36
|
-
version: 3.
|
38
|
+
version: 3.1.0
|
37
39
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
40
|
requirements:
|
39
41
|
- - ">="
|
40
42
|
- !ruby/object:Gem::Version
|
41
43
|
version: '0'
|
42
44
|
requirements: []
|
43
|
-
rubygems_version: 3.
|
45
|
+
rubygems_version: 3.3.27
|
46
|
+
signing_key:
|
44
47
|
specification_version: 4
|
45
48
|
summary: Expectation result presenter.
|
46
49
|
test_files: []
|