expresenter 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ddc8ef213f1b42ee370c0e8332886cc0c0a158197bda6eaba301f0a0edeae6f
4
- data.tar.gz: bee453e0190c6ce4e6a03955ad586af392ad424d2338196618ddcc608137d7ab
3
+ metadata.gz: 6701ed87c0d50891bb8804abc202aa3a2579d34f658b2d8b59f2b7caec76228a
4
+ data.tar.gz: f9d618cddd0aeacb36667da36816a759ff768aadb3e0f401f893baecf1306a2c
5
5
  SHA512:
6
- metadata.gz: 3589fcd607346650908c5c95f19eafe8a30813ccc869f2dde6c155112b3a9bbd64053d872f2de2c32eecc7ac520348043d9dd103bb9149c948dd76a5ad7856eb
7
- data.tar.gz: bbb3b0eaa9173024a9df1d6806bb243597fcfa1b7d7e7c96e68e70f5532bfa92eaf44d8b58b4cde56810ac6fed993775805677e52f17df474790de5f138b9600
6
+ metadata.gz: edbc7c35fe288a72bf3160810a5acf87675785e49f6f508ceb60a146ad74aa6072a2a287c24cde38a20ed22db242c7f1f2aeb6202e25f7cbaeacd1f5d39e622c
7
+ data.tar.gz: 2f16a23515e63fa17773da941ecb099a45c04a9973bcc5224d39ba36b41aff28f49d9e148960101bb49b8f0fca52b34c03c17848795bfb2f9ae4500d42c61d4b
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021-2024 Cyril Kato
3
+ Copyright (c) 2021-2025 Cyril Kato
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -2,20 +2,27 @@
2
2
 
3
3
  [![Version](https://img.shields.io/github/v/tag/fixrb/expresenter?label=Version&logo=github)](https://github.com/fixrb/expresenter/tags)
4
4
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/expresenter/main)
5
- [![Ruby](https://github.com/fixrb/expresenter/workflows/Ruby/badge.svg?branch=main)](https://github.com/fixrb/expresenter/actions?query=workflow%3Aruby+branch%3Amain)
6
- [![RuboCop](https://github.com/fixrb/expresenter/workflows/RuboCop/badge.svg?branch=main)](https://github.com/fixrb/expresenter/actions?query=workflow%3Arubocop+branch%3Amain)
7
5
  [![License](https://img.shields.io/github/license/fixrb/expresenter?label=License&logo=github)](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 formatting with colored output
14
- - Support for MUST/SHOULD/MAY requirement levels
15
- - Multiple result classification: success, warning, info, failure, and error
16
- - Emoji support for visual result indication (✅, ⚠️, 💡, ❌, 💥)
17
- - Flexible negation support for negative assertions
18
- - Detailed error reporting with custom messages
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
- Assuming that an expectation is an assertion that is either `true` or `false`,
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
- result = Expresenter.call(true).new(actual: "FOO", definition: 'eq "foo"', error: nil, got: true, negate: true, level: :MUST)
87
-
88
- result.failed? # => false
89
- result.failure? # => false
90
- result.info? # => false
91
- result.warning? # => false
92
- result.to_sym # => :success
93
- result.char # => "."
94
- result.emoji # => "✅"
95
- result.passed? # => true
96
- result.negate? # => true
97
- result.error? # => false
98
- result.success? # => true
99
- result.definition # => "eq \"foo\""
100
- result.summary # => "expected \"FOO\" not to eq \"foo\""
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
- A failed expectation:
69
+ ### Handling Different Result Types
109
70
 
110
71
  ```ruby
111
- result = Expresenter.call(false).new(actual: "foo", definition: "eq 42", error: Exception.new("BOOM"), got: true, negate: true, level: :MUST)
112
-
113
- result.failed? # => true
114
- result.failure? # => false
115
- result.info? # => false
116
- result.warning? # => false
117
- result.to_sym # => :error
118
- result.char # => "E"
119
- result.emoji # => "💥"
120
- result.passed? # => false
121
- result.negate? # => true
122
- result.error? # => true
123
- result.success? # => true
124
- result.definition # => "eq 42"
125
- result.summary # => "BOOM"
126
- result.colored_char # => "\e[31mE\e[0m"
127
- result.colored_string # => "\e[31m\e[1mException\e[22m: BOOM.\e[0m"
128
- result.message # => "Exception: BOOM."
129
- result.to_s # => "Exception: BOOM."
130
- result.titre # => "Exception"
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
- ### Return or Raise
104
+ ### Using Requirement Levels
134
105
 
135
- To return the results which pass, and to raise the results which fail, the `with` method is available.
106
+ Expresenter supports RFC 2119 requirement levels:
136
107
 
137
- In this example, the result passes, the instance is therefore returned:
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
- Expresenter.call(true).with(actual: "FOO", definition: 'eq "foo"', error: nil, got: true, negate: true, level: :MUST) # => Expresenter::Pass(actual: "FOO", definition: "eq \"foo\"", error: nil, got: true, negate: true, level: :MUST)
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
- In this example, the result fails, so the exception is raised:
126
+ ### Working with Negative Assertions
144
127
 
145
128
  ```ruby
146
- Expresenter.call(false).with(actual: "foo", definition: "eq 40", error: Exception.new("BOOM"), got: true, negate: true, level: :MUST)
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
- > Traceback (most recent call last):
150
- > 4: from ./bin/console:7:in `<main>'
151
- > 3: from (irb):42
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
- ### More Examples
147
+ Example integration with a test framework:
157
148
 
158
- A full list of unit tests can be viewed (and executed) here:
159
- [./test.rb](https://github.com/fixrb/expresenter/blob/main/test.rb)
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
- ## Contact
164
+ ## Development
162
165
 
163
- * Home page: https://github.com/fixrb/expresenter
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
- ## Versioning
168
+ ## Contributing
167
169
 
168
- __Expresenter__ follows [Semantic Versioning 2.0](https://semver.org/).
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
 
@@ -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
- # White space.
28
+ # String constant used for joining message parts.
29
+ #
30
+ # @api private
7
31
  SPACE = " "
8
32
 
9
- # @return [#object_id] Returned value by the challenged subject.
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
- # @return [String] A readable string of the matcher and any expected values.
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
- # @return [Exception, nil] Any possible raised exception.
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
- # @return [#object_id] The result of the boolean comparison between the
19
- # actual value and the expected value through the matcher.
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
- # @return [:MUST, :SHOULD, :MAY] The requirement level of the expectation.
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
- # Did the test pass?
74
+ # Checks if the test passed.
26
75
  #
27
- # @return [Boolean] The spec passed or failed?
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
- # The value of the negate instance variable.
83
+ # Checks if this is a negative assertion.
33
84
  #
34
- # @return [Boolean] Evaluated to a negative assertion?
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
- # The state of error.
93
+ # Checks if an error occurred during the test.
40
94
  #
41
- # @return [Boolean] The test raised an error?
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
- # The state of success.
107
+ # Checks if the test was successful.
47
108
  #
48
- # @return [Boolean] The test was a success?
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
- # The summary of the result.
117
+ # Generates a human-readable summary of the test result.
54
118
  #
55
- # @return [String] A string representing the summary of the result.
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
- # Express the result with one colored char.
134
+ # Returns the result indicator with ANSI color codes.
67
135
  #
68
- # @return [String] The colored char that identify the result.
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
- # The colored string representation of the result.
143
+ # Returns the full result message with ANSI color codes.
74
144
  #
75
- # @return [String] A string representing the result.
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
- # The representation of the result.
152
+ # Returns the complete result message.
81
153
  #
82
- # @return [String] A string representing the result.
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
- # Titre for the result.
161
+ # Returns the title for the result type.
88
162
  #
89
- # @return [String] A string representing the titre.
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
- # The negation, if any.
178
+ # Returns the negation word if this is a negative assertion.
101
179
  #
102
- # @return [String, nil] The negation, or an empty string.
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
- # The representation of the result with the title in bold.
186
+ # Returns the result message with a bold title.
108
187
  #
109
- # @return [String] A string representing the result with the title in bold.
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
@@ -3,38 +3,105 @@
3
3
  require_relative "common"
4
4
 
5
5
  module Expresenter
6
- # The class that is responsible for reporting that an expectation is false.
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
- # Char representing a failure.
52
+ # Single character indicator for test failures.
53
+ # @api private
9
54
  FAILURE_CHAR = "F"
10
55
 
11
- # Emoji representing a failure.
56
+ # Emoji indicator for test failures.
57
+ # @api private
12
58
  FAILURE_EMOJI = "❌"
13
59
 
14
- # Char representing an error.
60
+ # Single character indicator for test errors.
61
+ # @api private
15
62
  ERROR_CHAR = "E"
16
63
 
17
- # Emoji representing an error.
64
+ # Emoji indicator for test errors.
65
+ # @api private
18
66
  ERROR_EMOJI = "💥"
19
67
 
20
68
  include Common
21
69
 
22
- # @param (see Fail#initialize)
23
- # @raise [Fail] A failed spec exception.
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
- # Initialize method.
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
- # @param actual [#object_id] Returned value by the challenged subject.
31
- # @param definition [String] A readable string of the matcher and any
32
- # expected values.
33
- # @param error [Exception, nil] Any possible raised exception.
34
- # @param got [Boolean, nil] The result of the boolean comparison
35
- # between the actual value and the expected value through the matcher.
36
- # @param negate [Boolean] Evaluated to a negative assertion?
37
- # @param level [:MUST, :SHOULD, :MAY] The requirement level.
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
- # Did the test fail?
116
+ # Always returns true since this class represents failed tests.
50
117
  #
51
- # @return [Boolean] The spec passed or failed?
118
+ # @return [true] Always returns true
52
119
  def failed?
53
120
  true
54
121
  end
55
122
 
56
- # The state of failure.
123
+ # Indicates if this is a regular failure (not an error).
57
124
  #
58
- # @return [Boolean] The test was a failure?
125
+ # @return [Boolean] true if no error was captured, false otherwise
59
126
  def failure?
60
127
  !error?
61
128
  end
62
129
 
63
- # The state of info.
130
+ # Fail results are never informational.
64
131
  #
65
- # @return [Boolean] The test was an info?
132
+ # @return [false] Always returns false
66
133
  def info?
67
134
  false
68
135
  end
69
136
 
70
- # The state of warning.
137
+ # Fail results are never warnings.
71
138
  #
72
- # @return [Boolean] The test was a warning?
139
+ # @return [false] Always returns false
73
140
  def warning?
74
141
  false
75
142
  end
76
143
 
77
- # Identify the state of the result.
144
+ # Returns the symbolic representation of the failure type.
78
145
  #
79
- # @return [Symbol] The identifier of the state.
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
- # Express the result with one char.
155
+ # Returns a single character representing the failure type.
89
156
  #
90
- # @return [String] The char that identify the result.
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
- # Express the result with one emoji.
166
+ # Returns an emoji representing the failure type.
100
167
  #
101
- # @return [String] The emoji that identify the result.
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
@@ -3,46 +3,103 @@
3
3
  require_relative "common"
4
4
 
5
5
  module Expresenter
6
- # The class that is responsible for reporting that an expectation is true.
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
- # Char representing an info.
50
+ # Single character indicator for informational results.
51
+ # @api private
9
52
  INFO_CHAR = "I"
10
53
 
11
- # Emoji representing an info.
54
+ # Emoji indicator for informational results.
55
+ # @api private
12
56
  INFO_EMOJI = "💡"
13
57
 
14
- # Char representing a success.
58
+ # Single character indicator for successful results.
59
+ # @api private
15
60
  SUCCESS_CHAR = "."
16
61
 
17
- # Emoji representing a success.
62
+ # Emoji indicator for successful results.
63
+ # @api private
18
64
  SUCCESS_EMOJI = "✅"
19
65
 
20
- # Char representing a warning.
66
+ # Single character indicator for warning results.
67
+ # @api private
21
68
  WARNING_CHAR = "W"
22
69
 
23
- # Emoji representing a warning.
70
+ # Emoji indicator for warning results.
71
+ # @api private
24
72
  WARNING_EMOJI = "⚠️"
25
73
 
26
74
  include Common
27
75
 
28
- # @param (see Pass#initialize)
29
- # @return [Pass] A passed spec instance.
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
- # Initialize method.
95
+ # Initializes a new Pass instance.
37
96
  #
38
- # @param actual [#object_id] Returned value by the challenged subject.
39
- # @param definition [String] A readable string of the matcher and any
40
- # expected values.
41
- # @param error [Exception, nil] Any possible raised exception.
42
- # @param got [Boolean, nil] The result of the boolean comparison
43
- # between the actual value and the expected value through the matcher.
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
- # Did the test fail?
112
+ # Always returns false since this class represents passed tests.
56
113
  #
57
- # @return [Boolean] The spec passed or failed?
114
+ # @return [false] Always returns false
58
115
  def failed?
59
116
  false
60
117
  end
61
118
 
62
- # The state of failure.
119
+ # Pass results are never failures.
63
120
  #
64
- # @return [Boolean] The test was a failure?
121
+ # @return [false] Always returns false
65
122
  def failure?
66
123
  false
67
124
  end
68
125
 
69
- # The state of info.
126
+ # Indicates if this is an informational result.
70
127
  #
71
- # @return [Boolean] The test was an info?
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
- # The state of warning.
133
+ # Indicates if this is a warning result.
77
134
  #
78
- # @return [Boolean] The test was a warning?
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
- # Identify the state of the result.
140
+ # Returns the symbolic representation of the result state.
84
141
  #
85
- # @return [Symbol] The identifier of the state.
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
- # Express the result with one char.
153
+ # Returns a single character representing the result state.
97
154
  #
98
- # @return [String] The char that identify the result.
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
- # Express the result with one emoji.
166
+ # Returns an emoji representing the result state.
110
167
  #
111
- # @return [String] The emoji that identify the result.
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
- # @example A passed expectation result presenter.
6
- # Expresenter.call(true).with(actual: "FOO", definition: 'eql "foo"', error: nil, got: true, negate: true, level: :MUST) # => Expresenter::Pass(actual: "FOO", definition: "eql \"foo\"", error: nil, got: true, negate: true, level: :MUST)
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
- # @param is_passed [Boolean] The value of an assertion.
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
- # @return [Class<Pass>, Class<Fail>] The class of the result.
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.0
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-29 00:00:00.000000000 Z
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.2.0
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.6.2
45
+ rubygems_version: 3.3.27
46
+ signing_key:
44
47
  specification_version: 4
45
48
  summary: Expectation result presenter.
46
49
  test_files: []