rspec-enriched_json 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 897a7b35c81a2a9b629d4af420b37e5f404e360ad92d6bfb06a983c580687f2c
4
- data.tar.gz: 3907177ad79acea11dff76511d2fbb6d5577a6e234147a6a66b47519fdd3e527
3
+ metadata.gz: c155a0065925088da970a60a0c9d2ca9522fd1d50c15ac935a0e433b5fc7db34
4
+ data.tar.gz: 34ebf27abad693dd02c86a74508b9166d1e58eb9911cbf8432e1aefab00c1b04
5
5
  SHA512:
6
- metadata.gz: 5573a16911801b63c1210357122e97436e1cb5a5ad2d5e3addc089b8afd60bc3a1bb995c34a7a252f4ed926123e011f7c331c8ec681ad2907f6d079d946c4e95
7
- data.tar.gz: 6114b639b4b64796f06629cbf4ac5b323d62647175a10738af938236e1c261883097dc1d914fb179b5b2431d05063f5b2a28a6c0a72473b3546bed43c5c7255f
6
+ metadata.gz: 74be0b49aec163bb30b2d9924f617fcf001cd9994dd351e67e5962b48f53c1e005d0046acc03f78fcbeede84082a04984a08742b540d3835d648ff824d83c965
7
+ data.tar.gz: 933b7e250a69259b2781a23637bdf8b69543a941700c22eb174806f684a26e13dd9b3488a8839108ae0d29e7dde9138cb135a2b5daf49031041be7b69e72ceea
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "json"
4
4
  require "rspec/expectations"
5
+ require "rspec/support/differ"
5
6
 
6
7
  module RSpec
7
8
  module EnrichedJson
@@ -28,12 +29,16 @@ module RSpec
28
29
  return "[Max depth exceeded]" if depth > MAX_SERIALIZATION_DEPTH
29
30
 
30
31
  case value
31
- when nil, Numeric, TrueClass, FalseClass
32
+ when Numeric, TrueClass, FalseClass
32
33
  value
33
34
  when String
34
- truncate_string(value)
35
+ unescape_string_double_quotes(
36
+ truncate_string(value)
37
+ )
35
38
  when Symbol
36
- value.to_s
39
+ serialize_object(value)
40
+ when nil
41
+ serialize_object(value)
37
42
  when Array
38
43
  return "[Large array: #{value.size} items]" if value.size > MAX_ARRAY_SIZE
39
44
  value.map { |v| serialize_value(v, depth + 1) }
@@ -78,6 +83,14 @@ module RSpec
78
83
  "#{str[0...MAX_STRING_LENGTH]}... (truncated)"
79
84
  end
80
85
 
86
+ def unescape_string_double_quotes(str)
87
+ if str.start_with?('"') && str.end_with?('"')
88
+ return str.undump
89
+ else
90
+ str
91
+ end
92
+ end
93
+
81
94
  def safe_inspect(obj)
82
95
  truncate_string(obj.inspect)
83
96
  rescue => e
@@ -109,11 +122,21 @@ module RSpec
109
122
  details = {
110
123
  expected: Serializer.serialize_value(expected_raw),
111
124
  actual: Serializer.serialize_value(actual_raw),
112
- original_message: original_message, # Only populated when custom message overrides it
125
+ original_message: original_message, # Only populated when custom message overrides it
113
126
  matcher_name: matcher.class.name,
114
127
  diffable: values_diffable?(expected_raw, actual_raw, matcher)
115
128
  }
116
129
 
130
+ # Generate diff if values are diffable
131
+ if details[:diffable] && expected_raw && actual_raw
132
+ diff = generate_diff(actual_raw, expected_raw)
133
+ details[:diff] = diff unless diff.nil? || diff.strip.empty?
134
+ end
135
+
136
+ # Capture matcher-specific instance variables
137
+ matcher_data = extract_matcher_specific_data(matcher)
138
+ details.merge!(matcher_data) unless matcher_data.empty?
139
+
117
140
  # Raise new exception with data attached
118
141
  raise EnrichedExpectationNotMetError.new(e.message, details)
119
142
  end
@@ -131,6 +154,71 @@ module RSpec
131
154
  nil
132
155
  end
133
156
 
157
+ def extract_matcher_specific_data(matcher)
158
+ # Skip common instance variables that are already captured
159
+ skip_vars = [
160
+ :@expected, :@actual, :@args, :@name,
161
+ # Skip internal implementation details
162
+ :@matcher, :@matchers, :@target,
163
+ :@delegator, :@base_matcher,
164
+ :@block, :@event_proc,
165
+ # Skip verbose internal state
166
+ :@pairings_maximizer, :@best_solution,
167
+ :@expected_captures, :@match_captures,
168
+ :@failures, :@errors,
169
+ # Skip RSpec internals
170
+ :@matcher_execution_context,
171
+ :@chained_method_with_args_combos
172
+ ]
173
+
174
+ # Define meaningful variables we want to keep
175
+ useful_vars = [
176
+ :@missing_items, :@extra_items, # ContainExactly
177
+ :@expecteds, :@actuals, # Include
178
+ :@operator, :@delta, :@tolerance, # Comparison matchers
179
+ :@expected_before, :@expected_after, :@actual_before, :@actual_after, # Change matcher
180
+ :@from, :@to, :@minimum, :@maximum, :@count, # Various matchers
181
+ :@failure_message, :@failure_message_when_negated,
182
+ :@description
183
+ ]
184
+
185
+ # Get all instance variables
186
+ ivars = matcher.instance_variables - skip_vars
187
+ return {} if ivars.empty?
188
+
189
+ # Build a hash of matcher-specific data
190
+ matcher_data = {}
191
+
192
+ ivars.each do |ivar|
193
+ # Only include if it's in our useful list or looks like user data
194
+ unless useful_vars.include?(ivar) || ivar.to_s.match?(/^@(missing|extra|failed|unmatched|matched)_/)
195
+ next
196
+ end
197
+
198
+ value = matcher.instance_variable_get(ivar)
199
+
200
+ # Skip if value is nil or the matcher itself
201
+ next if value.nil? || value == matcher
202
+
203
+ # Skip procs and complex objects unless they're simple collections
204
+ if value.is_a?(Proc) || (value.is_a?(Object) && !value.is_a?(Enumerable) && !value.is_a?(Numeric) && !value.is_a?(String) && !value.is_a?(Symbol))
205
+ next
206
+ end
207
+
208
+ # Convert instance variable name to a more readable format
209
+ # @missing_items -> missing_items
210
+ key = ivar.to_s.delete_prefix("@").to_sym
211
+
212
+ # Serialize the value
213
+ matcher_data[key] = Serializer.serialize_value(value)
214
+ rescue
215
+ # Skip this instance variable if we can't serialize it
216
+ next
217
+ end
218
+
219
+ matcher_data
220
+ end
221
+
134
222
  def values_diffable?(expected, actual, matcher)
135
223
  # First check if the matcher itself declares diffability
136
224
  if matcher.respond_to?(:diffable?)
@@ -157,6 +245,20 @@ module RSpec
157
245
  # If any error occurs during checking, assume not diffable
158
246
  false
159
247
  end
248
+
249
+ def generate_diff(actual, expected)
250
+ # Use RSpec's own differ for consistency
251
+ differ = RSpec::Support::Differ.new(
252
+ object_preparer: lambda { |obj|
253
+ RSpec::Matchers::Composable.surface_descriptions_in(obj)
254
+ },
255
+ color: false # Always disable color for JSON output
256
+ )
257
+ differ.diff(actual, expected)
258
+ rescue
259
+ # If diff generation fails, return nil rather than crashing
260
+ nil
261
+ end
160
262
  end
161
263
  end
162
264
  end
@@ -28,6 +28,13 @@ module RSpec
28
28
  if e.is_a?(RSpec::EnrichedJson::EnrichedExpectationNotMetError) && e.details
29
29
  hash[:details] = safe_structured_data(e.details)
30
30
  end
31
+
32
+ if hash.key?(:details) && hash[:details].key?(:expected) && hash[:details].key?(:actual)
33
+ exception_message = hash[:exception][:message]
34
+ if exception_message.include?("\nDiff:")
35
+ hash[:exception][:message] = exception_message.sub(/Diff:.*/m, "").strip
36
+ end
37
+ end
31
38
  end
32
39
  end
33
40
  end
@@ -85,13 +92,22 @@ module RSpec
85
92
  end
86
93
 
87
94
  def safe_structured_data(details)
88
- {
95
+ # Start with core fields
96
+ result = {
89
97
  expected: safe_serialize(details[:expected]),
90
98
  actual: safe_serialize(details[:actual]),
91
99
  matcher_name: details[:matcher_name],
92
100
  original_message: details[:original_message],
93
101
  diffable: details[:diffable]
94
- }.compact
102
+ }
103
+
104
+ # Add any additional matcher-specific fields
105
+ details.each do |key, value|
106
+ next if [:expected, :actual, :matcher_name, :original_message, :diffable].include?(key)
107
+ result[key] = safe_serialize(value)
108
+ end
109
+
110
+ result.compact
95
111
  end
96
112
 
97
113
  def safe_serialize(value)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module EnrichedJson
5
- VERSION = "0.5.0"
5
+ VERSION = "0.6.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-enriched_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raghu Betina
@@ -120,7 +120,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
120
  - !ruby/object:Gem::Version
121
121
  version: '0'
122
122
  requirements: []
123
- rubygems_version: 3.6.9
123
+ rubygems_version: 3.6.7
124
124
  specification_version: 4
125
125
  summary: Enriches RSpec JSON output with structured failure data
126
126
  test_files: []