super_diff 0.6.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/super_diff.rb +24 -0
- data/lib/super_diff/diff_formatters/collection.rb +1 -1
- data/lib/super_diff/equality_matchers/array.rb +2 -2
- data/lib/super_diff/equality_matchers/default.rb +2 -2
- data/lib/super_diff/equality_matchers/hash.rb +2 -2
- data/lib/super_diff/equality_matchers/multiline_string.rb +2 -2
- data/lib/super_diff/equality_matchers/primitive.rb +2 -2
- data/lib/super_diff/equality_matchers/singleline_string.rb +2 -2
- data/lib/super_diff/object_inspection.rb +0 -8
- data/lib/super_diff/object_inspection/nodes/inspection.rb +1 -1
- data/lib/super_diff/rspec/monkey_patches.rb +343 -304
- data/lib/super_diff/version.rb +1 -1
- data/spec/combustion/Gemfile.lock +173 -0
- data/spec/examples.txt +403 -387
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/{object_inspection_spec.rb → super_diff_spec.rb} +136 -76
- metadata +6 -6
- data/spec/tmp/integration_spec.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: be7fd08d833b19c6a99401a1c7b80c448903c315d198b09e55baf70ee663dcfc
|
4
|
+
data.tar.gz: ea79d7bb6469e711058b71716c9ce1a23d6353381a8ae876c6bb180a57e78e2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75a1258f1d15d4a830a89ad898cefed4d6379d012fd7aa50d61f82672f10d0acacbf32e88177970fe46afa977dbce42c30212194867eefa1a72eb874417a1156
|
7
|
+
data.tar.gz: eb40c7881a21263fc89c6c2cfd1e54c5277449f98a32fb266bc720c43177772480d9834b61c4614102c236942d46ffcea82bc4e5090ad5f70dfc6d15f1d9e184
|
data/lib/super_diff.rb
CHANGED
@@ -30,10 +30,34 @@ module SuperDiff
|
|
30
30
|
@_configuration ||= Configuration.new
|
31
31
|
end
|
32
32
|
|
33
|
+
def self.inspect_object(object, as_single_line:, indent_level: 0)
|
34
|
+
ObjectInspection::Inspectors::Main.call(
|
35
|
+
object,
|
36
|
+
as_single_line: as_single_line,
|
37
|
+
indent_level: indent_level,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
33
41
|
def self.time_like?(value)
|
34
42
|
# Check for ActiveSupport's #acts_like_time? for their time-like objects
|
35
43
|
# (like ActiveSupport::TimeWithZone).
|
36
44
|
(value.respond_to?(:acts_like_time?) && value.acts_like_time?) ||
|
37
45
|
value.is_a?(Time)
|
38
46
|
end
|
47
|
+
|
48
|
+
def self.insert_overrides(target_module, mod = nil, &block)
|
49
|
+
if mod
|
50
|
+
target_module.prepend(mod)
|
51
|
+
else
|
52
|
+
target_module.prepend(Module.new(&block))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.insert_singleton_overrides(target_module, mod = nil, &block)
|
57
|
+
if mod
|
58
|
+
target_module.singleton_class.prepend(mod)
|
59
|
+
else
|
60
|
+
target_module.singleton_class.prepend(Module.new(&block))
|
61
|
+
end
|
62
|
+
end
|
39
63
|
end
|
@@ -13,14 +13,14 @@ module SuperDiff
|
|
13
13
|
Helpers.style(
|
14
14
|
:expected,
|
15
15
|
"Expected: " +
|
16
|
-
|
16
|
+
SuperDiff.inspect_object(expected, as_single_line: true),
|
17
17
|
)
|
18
18
|
}
|
19
19
|
#{
|
20
20
|
Helpers.style(
|
21
21
|
:actual,
|
22
22
|
" Actual: " +
|
23
|
-
|
23
|
+
SuperDiff.inspect_object(actual, as_single_line: true),
|
24
24
|
)
|
25
25
|
}
|
26
26
|
|
@@ -21,7 +21,7 @@ module SuperDiff
|
|
21
21
|
Helpers.style(
|
22
22
|
:expected,
|
23
23
|
"Expected: " +
|
24
|
-
|
24
|
+
SuperDiff.inspect_object(expected, as_single_line: true),
|
25
25
|
)
|
26
26
|
end
|
27
27
|
|
@@ -29,7 +29,7 @@ module SuperDiff
|
|
29
29
|
Helpers.style(
|
30
30
|
:actual,
|
31
31
|
" Actual: " +
|
32
|
-
|
32
|
+
SuperDiff.inspect_object(actual, as_single_line: true),
|
33
33
|
)
|
34
34
|
end
|
35
35
|
|
@@ -13,14 +13,14 @@ module SuperDiff
|
|
13
13
|
Helpers.style(
|
14
14
|
:expected,
|
15
15
|
"Expected: " +
|
16
|
-
|
16
|
+
SuperDiff.inspect_object(expected, as_single_line: true),
|
17
17
|
)
|
18
18
|
}
|
19
19
|
#{
|
20
20
|
Helpers.style(
|
21
21
|
:actual,
|
22
22
|
" Actual: " +
|
23
|
-
|
23
|
+
SuperDiff.inspect_object(actual, as_single_line: true),
|
24
24
|
)
|
25
25
|
}
|
26
26
|
|
@@ -14,14 +14,14 @@ module SuperDiff
|
|
14
14
|
Helpers.style(
|
15
15
|
:expected,
|
16
16
|
"Expected: " +
|
17
|
-
|
17
|
+
SuperDiff.inspect_object(expected, as_single_line: true),
|
18
18
|
)
|
19
19
|
}
|
20
20
|
#{
|
21
21
|
Helpers.style(
|
22
22
|
:actual,
|
23
23
|
" Actual: " +
|
24
|
-
|
24
|
+
SuperDiff.inspect_object(actual, as_single_line: true),
|
25
25
|
)
|
26
26
|
}
|
27
27
|
|
@@ -17,14 +17,14 @@ module SuperDiff
|
|
17
17
|
Helpers.style(
|
18
18
|
:expected,
|
19
19
|
"Expected: " +
|
20
|
-
|
20
|
+
SuperDiff.inspect_object(expected, as_single_line: true),
|
21
21
|
)
|
22
22
|
}
|
23
23
|
#{
|
24
24
|
Helpers.style(
|
25
25
|
:actual,
|
26
26
|
" Actual: " +
|
27
|
-
|
27
|
+
SuperDiff.inspect_object(actual, as_single_line: true),
|
28
28
|
)
|
29
29
|
}
|
30
30
|
OUTPUT
|
@@ -13,14 +13,14 @@ module SuperDiff
|
|
13
13
|
Helpers.style(
|
14
14
|
:expected,
|
15
15
|
"Expected: " +
|
16
|
-
|
16
|
+
SuperDiff.inspect_object(expected, as_single_line: true),
|
17
17
|
)
|
18
18
|
}
|
19
19
|
#{
|
20
20
|
Helpers.style(
|
21
21
|
:actual,
|
22
22
|
" Actual: " +
|
23
|
-
|
23
|
+
SuperDiff.inspect_object(actual, as_single_line: true),
|
24
24
|
)
|
25
25
|
}
|
26
26
|
OUTPUT
|
@@ -3,13 +3,5 @@ module SuperDiff
|
|
3
3
|
autoload :InspectionTree, "super_diff/object_inspection/inspection_tree"
|
4
4
|
autoload :Inspectors, "super_diff/object_inspection/inspectors"
|
5
5
|
autoload :Nodes, "super_diff/object_inspection/nodes"
|
6
|
-
|
7
|
-
def self.inspect(object, as_single_line:, indent_level: 0)
|
8
|
-
Inspectors::Main.call(
|
9
|
-
object,
|
10
|
-
as_single_line: as_single_line,
|
11
|
-
indent_level: indent_level,
|
12
|
-
)
|
13
|
-
end
|
14
6
|
end
|
15
7
|
end
|
@@ -12,34 +12,38 @@ require "rspec/matchers/built_in/match"
|
|
12
12
|
|
13
13
|
module RSpec
|
14
14
|
module Expectations
|
15
|
-
|
16
|
-
|
15
|
+
SuperDiff.insert_singleton_overrides(self) do
|
16
|
+
def differ
|
17
|
+
SuperDiff::RSpec::Differ
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
module ExpectationHelper
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
matcher.expected_for_diff
|
29
|
-
|
30
|
-
|
31
|
-
|
22
|
+
SuperDiff.insert_singleton_overrides(self) do
|
23
|
+
def handle_failure(matcher, message, failure_message_method)
|
24
|
+
message = message.call if message.respond_to?(:call)
|
25
|
+
message ||= matcher.__send__(failure_message_method)
|
26
|
+
|
27
|
+
if matcher.respond_to?(:diffable?) && matcher.diffable?
|
28
|
+
# Look for expected_for_diff and actual_for_diff if possible
|
29
|
+
expected =
|
30
|
+
if matcher.respond_to?(:expected_for_diff)
|
31
|
+
matcher.expected_for_diff
|
32
|
+
else
|
33
|
+
matcher.expected
|
34
|
+
end
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
actual =
|
37
|
+
if matcher.respond_to?(:actual_for_diff)
|
38
|
+
matcher.actual_for_diff
|
39
|
+
else
|
40
|
+
matcher.actual
|
41
|
+
end
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
::RSpec::Expectations.fail_with(message, expected, actual)
|
44
|
+
else
|
45
|
+
::RSpec::Expectations.fail_with(message)
|
46
|
+
end
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -48,29 +52,31 @@ module RSpec
|
|
48
52
|
module Core
|
49
53
|
module Formatters
|
50
54
|
module ConsoleCodes
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
if
|
57
|
-
|
58
|
-
|
59
|
-
code_or_symbol
|
60
|
-
else
|
61
|
-
RSpec::Core::Formatters::ConsoleCodes::VT100_CODES.fetch(code_or_symbol) do
|
55
|
+
SuperDiff.insert_singleton_overrides(self) do
|
56
|
+
# Patch so it returns nothing if code_or_symbol is nil, and that it uses
|
57
|
+
# code_or_symbol if it can't be found in VT100_CODE_VALUES to allow for
|
58
|
+
# customization
|
59
|
+
def console_code_for(code_or_symbol)
|
60
|
+
if code_or_symbol
|
61
|
+
if (config_method = config_colors_to_methods[code_or_symbol])
|
62
|
+
console_code_for RSpec.configuration.__send__(config_method)
|
63
|
+
elsif RSpec::Core::Formatters::ConsoleCodes::VT100_CODE_VALUES.key?(code_or_symbol)
|
62
64
|
code_or_symbol
|
65
|
+
else
|
66
|
+
RSpec::Core::Formatters::ConsoleCodes::VT100_CODES.fetch(code_or_symbol) do
|
67
|
+
code_or_symbol
|
68
|
+
end
|
63
69
|
end
|
64
70
|
end
|
65
71
|
end
|
66
|
-
end
|
67
72
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
73
|
+
# Patch so it does not apply a color if code_or_symbol is nil
|
74
|
+
def wrap(text, code_or_symbol)
|
75
|
+
if RSpec.configuration.color_enabled? && code = console_code_for(code_or_symbol)
|
76
|
+
"\e[#{code}m#{text}\e[0m"
|
77
|
+
else
|
78
|
+
text
|
79
|
+
end
|
74
80
|
end
|
75
81
|
end
|
76
82
|
end
|
@@ -79,173 +85,177 @@ module RSpec
|
|
79
85
|
# UPDATE: Copy from SyntaxHighlighter::CodeRayImplementation
|
80
86
|
RESET_CODE = "\e[0m"
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
88
|
+
SuperDiff.insert_overrides(self) do
|
89
|
+
def initialize(exception, example, options={})
|
90
|
+
@exception = exception
|
91
|
+
@example = example
|
92
|
+
@message_color = options.fetch(:message_color) { RSpec.configuration.failure_color }
|
93
|
+
@description = options.fetch(:description) { example.full_description }
|
94
|
+
@detail_formatter = options.fetch(:detail_formatter) { Proc.new {} }
|
95
|
+
@extra_detail_formatter = options.fetch(:extra_detail_formatter) { Proc.new {} }
|
96
|
+
@backtrace_formatter = options.fetch(:backtrace_formatter) { RSpec.configuration.backtrace_formatter }
|
97
|
+
@indentation = options.fetch(:indentation, 2)
|
98
|
+
@skip_shared_group_trace = options.fetch(:skip_shared_group_trace, false)
|
99
|
+
# Patch to convert options[:failure_lines] to groups
|
100
|
+
if options.include?(:failure_lines)
|
101
|
+
@failure_line_groups = [
|
102
|
+
{
|
103
|
+
lines: options[:failure_lines],
|
104
|
+
already_colorized: false
|
105
|
+
}
|
106
|
+
]
|
107
|
+
end
|
100
108
|
end
|
101
|
-
end
|
102
109
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
else
|
114
|
-
indentation = line[/^[ ]+/]
|
115
|
-
rest = colorizer.wrap(line.sub(/^[ ]+/, ''), message_color)
|
116
|
-
|
117
|
-
if indentation
|
118
|
-
indentation + rest
|
110
|
+
# Override to only color uncolored lines in red
|
111
|
+
# and to not color empty lines
|
112
|
+
def colorized_message_lines(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
|
113
|
+
lines = failure_line_groups.flat_map do |group|
|
114
|
+
if group[:already_colorized]
|
115
|
+
group[:lines]
|
116
|
+
else
|
117
|
+
group[:lines].map do |line|
|
118
|
+
if line.strip.empty?
|
119
|
+
line
|
119
120
|
else
|
120
|
-
|
121
|
+
indentation = line[/^[ ]+/]
|
122
|
+
rest = colorizer.wrap(line.sub(/^[ ]+/, ''), message_color)
|
123
|
+
|
124
|
+
if indentation
|
125
|
+
indentation + rest
|
126
|
+
else
|
127
|
+
rest
|
128
|
+
end
|
121
129
|
end
|
122
130
|
end
|
123
131
|
end
|
124
132
|
end
|
125
|
-
end
|
126
|
-
|
127
|
-
add_shared_group_lines(lines, colorizer)
|
128
|
-
end
|
129
|
-
|
130
|
-
private
|
131
133
|
|
132
|
-
|
133
|
-
return lines if @skip_shared_group_trace
|
134
|
-
|
135
|
-
example.metadata[:shared_group_inclusion_backtrace].each do |frame|
|
136
|
-
# Use red instead of the default color
|
137
|
-
lines << colorizer.wrap(frame.description, :failure)
|
134
|
+
add_shared_group_lines(lines, colorizer)
|
138
135
|
end
|
139
136
|
|
140
|
-
|
141
|
-
end
|
137
|
+
private
|
142
138
|
|
143
|
-
|
144
|
-
|
145
|
-
# later
|
146
|
-
#
|
147
|
-
# TODO: Refactor this somehow
|
148
|
-
#
|
149
|
-
def failure_line_groups
|
150
|
-
if defined?(@failure_line_groups)
|
151
|
-
@failure_line_groups
|
152
|
-
else
|
153
|
-
@failure_line_groups = [
|
154
|
-
{
|
155
|
-
lines: failure_slash_error_lines,
|
156
|
-
already_colorized: true
|
157
|
-
}
|
158
|
-
]
|
159
|
-
|
160
|
-
sections = [failure_slash_error_lines, exception_lines]
|
161
|
-
separate_groups = (
|
162
|
-
sections.any? { |section| section.size > 1 } &&
|
163
|
-
!exception_lines.first.empty?
|
164
|
-
)
|
139
|
+
def add_shared_group_lines(lines, colorizer)
|
140
|
+
return lines if @skip_shared_group_trace
|
165
141
|
|
166
|
-
|
167
|
-
|
142
|
+
example.metadata[:shared_group_inclusion_backtrace].each do |frame|
|
143
|
+
# Use red instead of the default color
|
144
|
+
lines << colorizer.wrap(frame.description, :failure)
|
168
145
|
end
|
169
146
|
|
170
|
-
|
171
|
-
|
172
|
-
end
|
147
|
+
lines
|
148
|
+
end
|
173
149
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
150
|
+
# Considering that `failure_slash_error_lines` is already colored,
|
151
|
+
# extract this from the other lines so that they, too, can be colored,
|
152
|
+
# later
|
153
|
+
#
|
154
|
+
# TODO: Refactor this somehow
|
155
|
+
#
|
156
|
+
def failure_line_groups
|
157
|
+
if defined?(@failure_line_groups)
|
158
|
+
@failure_line_groups
|
179
159
|
else
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
160
|
+
@failure_line_groups = [
|
161
|
+
{
|
162
|
+
lines: failure_slash_error_lines,
|
163
|
+
already_colorized: true
|
164
|
+
}
|
165
|
+
]
|
184
166
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
167
|
+
sections = [failure_slash_error_lines, exception_lines]
|
168
|
+
separate_groups = (
|
169
|
+
sections.any? { |section| section.size > 1 } &&
|
170
|
+
!exception_lines.first.empty?
|
171
|
+
)
|
189
172
|
|
190
|
-
if
|
191
|
-
@failure_line_groups << {
|
192
|
-
|
193
|
-
|
194
|
-
|
173
|
+
if separate_groups
|
174
|
+
@failure_line_groups << { lines: [''], already_colorized: true }
|
175
|
+
end
|
176
|
+
|
177
|
+
already_colorized = exception_lines.any? do |line|
|
178
|
+
SuperDiff::Csi.already_colorized?(line)
|
179
|
+
end
|
180
|
+
|
181
|
+
if already_colorized
|
195
182
|
@failure_line_groups << {
|
196
|
-
lines: exception_lines
|
183
|
+
lines: exception_lines,
|
197
184
|
already_colorized: true
|
198
185
|
}
|
199
186
|
else
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
187
|
+
locatable_exception_lines =
|
188
|
+
exception_lines.each_with_index.map do |line, index|
|
189
|
+
{ text: line, index: index }
|
190
|
+
end
|
191
|
+
|
192
|
+
boundary_line =
|
193
|
+
locatable_exception_lines.find do |line, index|
|
194
|
+
line[:text].strip.empty? || line[:text].match?(/^ /)
|
195
|
+
end
|
196
|
+
|
197
|
+
if boundary_line
|
198
|
+
@failure_line_groups << {
|
199
|
+
lines: exception_lines[0..boundary_line[:index] - 1],
|
200
|
+
already_colorized: false
|
201
|
+
}
|
202
|
+
@failure_line_groups << {
|
203
|
+
lines: exception_lines[boundary_line[:index]..-1],
|
204
|
+
already_colorized: true
|
205
|
+
}
|
206
|
+
else
|
207
|
+
@failure_line_groups << {
|
208
|
+
lines: exception_lines,
|
209
|
+
already_colorized: false
|
210
|
+
}
|
211
|
+
end
|
204
212
|
end
|
205
|
-
end
|
206
213
|
|
207
|
-
|
214
|
+
@failure_line_groups
|
215
|
+
end
|
208
216
|
end
|
209
|
-
end
|
210
217
|
|
211
|
-
|
212
|
-
|
213
|
-
|
218
|
+
# Style the first part in white and don't style the snippet of the line
|
219
|
+
def failure_slash_error_lines
|
220
|
+
lines = read_failed_lines
|
214
221
|
|
215
|
-
|
222
|
+
failure_slash_error = ConsoleCodes.wrap("Failure/Error: ", :bold)
|
216
223
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
224
|
+
if lines.count == 1
|
225
|
+
lines[0] = failure_slash_error + lines[0].strip
|
226
|
+
else
|
227
|
+
least_indentation = SnippetExtractor.least_indentation_from(lines)
|
228
|
+
lines = lines.map do |line|
|
229
|
+
line.sub(/^#{least_indentation}/, ' ')
|
230
|
+
end
|
231
|
+
lines.unshift(failure_slash_error)
|
223
232
|
end
|
224
|
-
|
233
|
+
|
234
|
+
lines
|
225
235
|
end
|
226
236
|
|
227
|
-
|
228
|
-
|
237
|
+
# Exclude this file from being included in backtraces, so that the
|
238
|
+
# SnippetExtractor prints the right thing
|
239
|
+
def find_failed_line
|
240
|
+
line_regex = RSpec.configuration.in_project_source_dir_regex
|
241
|
+
loaded_spec_files = RSpec.configuration.loaded_spec_files
|
229
242
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
exception_backtrace.find do |line|
|
237
|
-
next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
|
238
|
-
path = File.expand_path(line_path)
|
239
|
-
path != __FILE__ && (loaded_spec_files.include?(path) || path =~ line_regex)
|
240
|
-
end || exception_backtrace.first
|
243
|
+
exception_backtrace.find do |line|
|
244
|
+
next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
|
245
|
+
path = File.expand_path(line_path)
|
246
|
+
path != __FILE__ && (loaded_spec_files.include?(path) || path =~ line_regex)
|
247
|
+
end || exception_backtrace.first
|
248
|
+
end
|
241
249
|
end
|
242
250
|
end
|
243
251
|
|
244
252
|
class SyntaxHighlighter
|
245
|
-
|
253
|
+
SuperDiff.insert_overrides(self) do
|
254
|
+
private
|
246
255
|
|
247
|
-
|
248
|
-
|
256
|
+
def implementation
|
257
|
+
RSpec::Core::Formatters::SyntaxHighlighter::NoSyntaxHighlightingImplementation
|
258
|
+
end
|
249
259
|
end
|
250
260
|
end
|
251
261
|
end
|
@@ -253,100 +263,108 @@ module RSpec
|
|
253
263
|
|
254
264
|
module Support
|
255
265
|
class ObjectFormatter
|
256
|
-
|
257
|
-
|
258
|
-
|
266
|
+
SuperDiff.insert_singleton_overrides(self) do
|
267
|
+
# Override to use our formatting algorithm
|
268
|
+
def format(value)
|
269
|
+
SuperDiff.inspect_object(value, as_single_line: true)
|
270
|
+
end
|
259
271
|
end
|
260
272
|
|
261
|
-
|
262
|
-
|
263
|
-
|
273
|
+
SuperDiff.insert_overrides(self) do
|
274
|
+
# Override to use our formatting algorithm
|
275
|
+
def format(value)
|
276
|
+
SuperDiff.inspect_object(value, as_single_line: true)
|
277
|
+
end
|
264
278
|
end
|
265
279
|
end
|
266
280
|
end
|
267
281
|
|
268
282
|
module Matchers
|
269
283
|
class ExpectedsForMultipleDiffs
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
new([[expected, text]])
|
306
|
-
end
|
284
|
+
SuperDiff.insert_singleton_overrides(self) do
|
285
|
+
# Add a key for different sides
|
286
|
+
def from(expected)
|
287
|
+
return expected if self === expected
|
288
|
+
|
289
|
+
text =
|
290
|
+
colorizer.wrap("Diff:", SuperDiff.configuration.header_color) +
|
291
|
+
"\n\n" +
|
292
|
+
colorizer.wrap(
|
293
|
+
"┌ (Key) ──────────────────────────┐",
|
294
|
+
SuperDiff.configuration.border_color
|
295
|
+
) +
|
296
|
+
"\n" +
|
297
|
+
colorizer.wrap("│ ", SuperDiff.configuration.border_color) +
|
298
|
+
colorizer.wrap(
|
299
|
+
"‹-› in expected, not in actual",
|
300
|
+
SuperDiff.configuration.expected_color
|
301
|
+
) +
|
302
|
+
colorizer.wrap(" │", SuperDiff.configuration.border_color) +
|
303
|
+
"\n" +
|
304
|
+
colorizer.wrap("│ ", SuperDiff.configuration.border_color) +
|
305
|
+
colorizer.wrap(
|
306
|
+
"‹+› in actual, not in expected",
|
307
|
+
SuperDiff.configuration.actual_color
|
308
|
+
) +
|
309
|
+
colorizer.wrap(" │", SuperDiff.configuration.border_color) +
|
310
|
+
"\n" +
|
311
|
+
colorizer.wrap("│ ", SuperDiff.configuration.border_color) +
|
312
|
+
"‹ › in both expected and actual" +
|
313
|
+
colorizer.wrap(" │", SuperDiff.configuration.border_color) +
|
314
|
+
"\n" +
|
315
|
+
colorizer.wrap(
|
316
|
+
"└─────────────────────────────────┘",
|
317
|
+
SuperDiff.configuration.border_color
|
318
|
+
)
|
307
319
|
|
308
|
-
|
309
|
-
|
320
|
+
new([[expected, text]])
|
321
|
+
end
|
322
|
+
|
323
|
+
def colorizer
|
324
|
+
RSpec::Core::Formatters::ConsoleCodes
|
325
|
+
end
|
310
326
|
end
|
311
327
|
|
312
|
-
|
313
|
-
|
314
|
-
|
328
|
+
SuperDiff.insert_overrides(self) do
|
329
|
+
# Add an extra line break
|
330
|
+
def message_with_diff(message, differ, actual)
|
331
|
+
diff = diffs(differ, actual)
|
315
332
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
333
|
+
if diff.empty?
|
334
|
+
message
|
335
|
+
else
|
336
|
+
"#{message.rstrip}\n\n#{diff}"
|
337
|
+
end
|
320
338
|
end
|
321
|
-
end
|
322
339
|
|
323
|
-
|
340
|
+
private
|
324
341
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
342
|
+
# Add extra line breaks in between diffs, and colorize the word "Diff"
|
343
|
+
def diffs(differ, actual)
|
344
|
+
@expected_list.map do |(expected, diff_label)|
|
345
|
+
diff = differ.diff(actual, expected)
|
346
|
+
next if diff.strip.empty?
|
347
|
+
diff_label + diff
|
348
|
+
end.compact.join("\n\n")
|
349
|
+
end
|
332
350
|
end
|
333
351
|
end
|
334
352
|
|
335
353
|
module BuiltIn
|
336
354
|
class Be
|
337
|
-
|
355
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
338
356
|
|
339
|
-
|
357
|
+
SuperDiff.insert_overrides(self) do
|
340
358
|
def expected_for_matcher_text
|
341
359
|
"truthy"
|
342
360
|
end
|
343
|
-
end
|
361
|
+
end
|
344
362
|
end
|
345
363
|
|
346
364
|
class BeComparedTo
|
347
|
-
|
365
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
348
366
|
|
349
|
-
|
367
|
+
SuperDiff.insert_overrides(self) do
|
350
368
|
def expected_action_for_matcher_text
|
351
369
|
if [:==, :===, :=~].include?(@operator)
|
352
370
|
"#{@operator}"
|
@@ -354,13 +372,13 @@ module RSpec
|
|
354
372
|
"be #{@operator}"
|
355
373
|
end
|
356
374
|
end
|
357
|
-
end
|
375
|
+
end
|
358
376
|
end
|
359
377
|
|
360
378
|
class BeFalsey
|
361
|
-
|
379
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
362
380
|
|
363
|
-
|
381
|
+
SuperDiff.insert_overrides(self) do
|
364
382
|
def expected_action_for_matcher_text
|
365
383
|
"be"
|
366
384
|
end
|
@@ -368,13 +386,13 @@ module RSpec
|
|
368
386
|
def expected_for_matcher_text
|
369
387
|
"falsey"
|
370
388
|
end
|
371
|
-
end
|
389
|
+
end
|
372
390
|
end
|
373
391
|
|
374
392
|
class BeNil
|
375
|
-
|
393
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
376
394
|
|
377
|
-
|
395
|
+
SuperDiff.insert_overrides(self) do
|
378
396
|
def expected_action_for_matcher_text
|
379
397
|
"be"
|
380
398
|
end
|
@@ -382,13 +400,13 @@ module RSpec
|
|
382
400
|
def expected_for_matcher_text
|
383
401
|
"nil"
|
384
402
|
end
|
385
|
-
end
|
403
|
+
end
|
386
404
|
end
|
387
405
|
|
388
406
|
class BePredicate
|
389
|
-
|
407
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
390
408
|
|
391
|
-
|
409
|
+
SuperDiff.insert_overrides(self) do
|
392
410
|
def actual_for_matcher_text
|
393
411
|
actual
|
394
412
|
end
|
@@ -416,13 +434,13 @@ module RSpec
|
|
416
434
|
expected_predicate_method_name: predicate
|
417
435
|
)
|
418
436
|
end
|
419
|
-
end
|
437
|
+
end
|
420
438
|
end
|
421
439
|
|
422
440
|
class BeTruthy
|
423
|
-
|
441
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
424
442
|
|
425
|
-
|
443
|
+
SuperDiff.insert_overrides(self) do
|
426
444
|
def expected_action_for_matcher_text
|
427
445
|
"be"
|
428
446
|
end
|
@@ -430,13 +448,13 @@ module RSpec
|
|
430
448
|
def expected_for_matcher_text
|
431
449
|
"truthy"
|
432
450
|
end
|
433
|
-
end
|
451
|
+
end
|
434
452
|
end
|
435
453
|
|
436
454
|
class ContainExactly
|
437
|
-
|
455
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
438
456
|
|
439
|
-
|
457
|
+
SuperDiff.insert_overrides(self) do
|
440
458
|
# Override this method so that the differ knows that this is a partial
|
441
459
|
# collection
|
442
460
|
def expected_for_diff
|
@@ -452,21 +470,26 @@ module RSpec
|
|
452
470
|
def matcher_text_builder_class
|
453
471
|
SuperDiff::RSpec::MatcherTextBuilders::ContainExactly
|
454
472
|
end
|
455
|
-
end
|
473
|
+
end
|
456
474
|
end
|
457
475
|
|
458
476
|
class Eq
|
459
|
-
|
477
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
460
478
|
end
|
461
479
|
|
462
480
|
class Equal
|
463
|
-
|
481
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
464
482
|
end
|
465
483
|
|
466
484
|
class HaveAttributes
|
467
|
-
|
485
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
486
|
+
|
487
|
+
SuperDiff.insert_overrides(self) do
|
488
|
+
def initialize(*)
|
489
|
+
super
|
490
|
+
@actual = nil
|
491
|
+
end
|
468
492
|
|
469
|
-
prepend(Module.new do
|
470
493
|
# Use the message in the base matcher
|
471
494
|
def failure_message
|
472
495
|
respond_to_failure_message_or { super }
|
@@ -502,48 +525,48 @@ module RSpec
|
|
502
525
|
matchers.an_object_having_attributes(@expected)
|
503
526
|
end
|
504
527
|
end
|
505
|
-
end)
|
506
528
|
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
529
|
+
# Override to force @values to get populated so that we can show a
|
530
|
+
# proper diff
|
531
|
+
def respond_to_attributes?
|
532
|
+
cache_all_values
|
533
|
+
matches = respond_to_matcher.matches?(@actual)
|
534
|
+
@respond_to_failed = !matches
|
535
|
+
matches
|
536
|
+
end
|
515
537
|
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
538
|
+
# Override this method to skip non-existent attributes, and to use
|
539
|
+
# public_send
|
540
|
+
def cache_all_values
|
541
|
+
@values = @expected.keys.inject({}) do |hash, attribute_key|
|
542
|
+
if @actual.respond_to?(attribute_key)
|
543
|
+
actual_value = @actual.public_send(attribute_key)
|
544
|
+
hash.merge(attribute_key => actual_value)
|
545
|
+
else
|
546
|
+
hash
|
547
|
+
end
|
525
548
|
end
|
526
549
|
end
|
527
|
-
end
|
528
550
|
|
529
|
-
|
530
|
-
|
531
|
-
|
551
|
+
def actual_has_attribute?(attribute_key, attribute_value)
|
552
|
+
values_match?(attribute_value, @values.fetch(attribute_key))
|
553
|
+
end
|
532
554
|
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
555
|
+
# Override to not improve_hash_formatting
|
556
|
+
def respond_to_failure_message_or
|
557
|
+
if respond_to_failed
|
558
|
+
respond_to_matcher.failure_message
|
559
|
+
else
|
560
|
+
yield
|
561
|
+
end
|
539
562
|
end
|
540
563
|
end
|
541
564
|
end
|
542
565
|
|
543
566
|
class Has
|
544
|
-
|
567
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
545
568
|
|
546
|
-
|
569
|
+
SuperDiff.insert_overrides(self) do
|
547
570
|
def actual_for_matcher_text
|
548
571
|
actual
|
549
572
|
end
|
@@ -570,13 +593,18 @@ module RSpec
|
|
570
593
|
private_predicate: private_predicate?
|
571
594
|
)
|
572
595
|
end
|
573
|
-
end
|
596
|
+
end
|
574
597
|
end
|
575
598
|
|
576
599
|
class Include
|
577
|
-
|
600
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
601
|
+
|
602
|
+
SuperDiff.insert_overrides(self) do
|
603
|
+
def initialize(*)
|
604
|
+
super
|
605
|
+
@actual = nil
|
606
|
+
end
|
578
607
|
|
579
|
-
prepend(Module.new do
|
580
608
|
# Override this method so that the differ knows that this is a partial
|
581
609
|
# array or hash
|
582
610
|
def expected_for_diff
|
@@ -611,7 +639,11 @@ module RSpec
|
|
611
639
|
def expected_for_failure_message
|
612
640
|
# TODO: Switch to using @divergent_items and handle this in the text
|
613
641
|
# builder
|
614
|
-
|
642
|
+
if defined?(@divergent_items)
|
643
|
+
readable_list_of(@divergent_items).lstrip
|
644
|
+
else
|
645
|
+
""
|
646
|
+
end
|
615
647
|
end
|
616
648
|
|
617
649
|
# Update to use (...) as delimiter instead of {...}
|
@@ -624,13 +656,13 @@ module RSpec
|
|
624
656
|
super
|
625
657
|
end
|
626
658
|
end
|
627
|
-
end
|
659
|
+
end
|
628
660
|
end
|
629
661
|
|
630
662
|
class Match
|
631
|
-
|
663
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
632
664
|
|
633
|
-
|
665
|
+
SuperDiff.insert_overrides(self) do
|
634
666
|
def matcher_text_builder_class
|
635
667
|
SuperDiff::RSpec::MatcherTextBuilders::Match
|
636
668
|
end
|
@@ -638,7 +670,7 @@ module RSpec
|
|
638
670
|
def matcher_text_builder_args
|
639
671
|
super.merge(expected_captures: @expected_captures)
|
640
672
|
end
|
641
|
-
end
|
673
|
+
end
|
642
674
|
end
|
643
675
|
|
644
676
|
class MatchArray < ContainExactly
|
@@ -652,9 +684,9 @@ module RSpec
|
|
652
684
|
end
|
653
685
|
|
654
686
|
class RaiseError
|
655
|
-
|
687
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
656
688
|
|
657
|
-
|
689
|
+
SuperDiff.insert_overrides(self) do
|
658
690
|
def actual_for_matcher_text
|
659
691
|
if @actual_error
|
660
692
|
"#<#{@actual_error.class.name} #{@actual_error.message.inspect}>"
|
@@ -696,7 +728,7 @@ module RSpec
|
|
696
728
|
def matcher_text_builder_class
|
697
729
|
SuperDiff::RSpec::MatcherTextBuilders::RaiseError
|
698
730
|
end
|
699
|
-
end
|
731
|
+
end
|
700
732
|
|
701
733
|
def self.matcher_name
|
702
734
|
"raise error"
|
@@ -704,9 +736,9 @@ module RSpec
|
|
704
736
|
end
|
705
737
|
|
706
738
|
class RespondTo
|
707
|
-
|
739
|
+
SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
|
708
740
|
|
709
|
-
|
741
|
+
SuperDiff.insert_overrides(self) do
|
710
742
|
def initialize(*)
|
711
743
|
super
|
712
744
|
@failing_method_names = nil
|
@@ -732,13 +764,20 @@ module RSpec
|
|
732
764
|
def expected_for_failure_message
|
733
765
|
@failing_method_names
|
734
766
|
end
|
735
|
-
end
|
767
|
+
end
|
736
768
|
end
|
737
769
|
end
|
738
770
|
|
739
|
-
|
740
|
-
|
771
|
+
SuperDiff.insert_overrides(self) do
|
772
|
+
def self.prepended(base)
|
773
|
+
base.class_eval do
|
774
|
+
alias_matcher :an_array_matching, :match_array
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
def match_array(items)
|
779
|
+
BuiltIn::MatchArray.new(items.is_a?(String) ? [items] : items)
|
780
|
+
end
|
741
781
|
end
|
742
|
-
alias_matcher :an_array_matching, :match_array
|
743
782
|
end
|
744
783
|
end
|