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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c155a0065925088da970a60a0c9d2ca9522fd1d50c15ac935a0e433b5fc7db34
|
4
|
+
data.tar.gz: 34ebf27abad693dd02c86a74508b9166d1e58eb9911cbf8432e1aefab00c1b04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
32
|
+
when Numeric, TrueClass, FalseClass
|
32
33
|
value
|
33
34
|
when String
|
34
|
-
|
35
|
+
unescape_string_double_quotes(
|
36
|
+
truncate_string(value)
|
37
|
+
)
|
35
38
|
when Symbol
|
36
|
-
value
|
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,
|
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
|
-
}
|
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)
|
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.
|
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.
|
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: []
|