super_diff 0.3.0 → 0.4.0
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/README.md +3 -3
- data/lib/super_diff/active_record.rb +2 -0
- data/lib/super_diff/active_record/monkey_patches.rb +9 -0
- data/lib/super_diff/csi.rb +4 -0
- data/lib/super_diff/equality_matchers/default.rb +1 -1
- data/lib/super_diff/operation_sequences/base.rb +14 -0
- data/lib/super_diff/rspec.rb +9 -9
- data/lib/super_diff/rspec/differ.rb +6 -6
- data/lib/super_diff/rspec/differs.rb +9 -3
- data/lib/super_diff/rspec/differs/collection_containing_exactly.rb +1 -1
- data/lib/super_diff/rspec/differs/{partial_hash.rb → collection_including.rb} +4 -3
- data/lib/super_diff/rspec/differs/{partial_array.rb → hash_including.rb} +4 -3
- data/lib/super_diff/rspec/differs/{partial_object.rb → object_having_attributes.rb} +3 -3
- data/lib/super_diff/rspec/matcher_text_builders.rb +4 -0
- data/lib/super_diff/rspec/matcher_text_builders/be_predicate.rb +26 -7
- data/lib/super_diff/rspec/matcher_text_builders/have_predicate.rb +61 -0
- data/lib/super_diff/rspec/matcher_text_builders/raise_error.rb +13 -1
- data/lib/super_diff/rspec/monkey_patches.rb +218 -111
- data/lib/super_diff/rspec/object_inspection/inspectors.rb +6 -6
- data/lib/super_diff/rspec/object_inspection/inspectors/{partial_array.rb → collection_including.rb} +2 -2
- data/lib/super_diff/rspec/object_inspection/inspectors/{partial_hash.rb → hash_including.rb} +1 -1
- data/lib/super_diff/rspec/object_inspection/inspectors/object_having_attributes.rb +22 -0
- data/lib/super_diff/rspec/object_inspection/map_extension.rb +7 -7
- data/lib/super_diff/rspec/operational_sequencers.rb +6 -6
- data/lib/super_diff/rspec/operational_sequencers/collection_containing_exactly.rb +1 -1
- data/lib/super_diff/rspec/operational_sequencers/{partial_array.rb → collection_including.rb} +3 -2
- data/lib/super_diff/rspec/operational_sequencers/{partial_hash.rb → hash_including.rb} +3 -2
- data/lib/super_diff/rspec/operational_sequencers/{partial_object.rb → object_having_attributes.rb} +2 -4
- data/lib/super_diff/version.rb +1 -1
- data/spec/integration/rails/active_record_spec.rb +1 -1
- data/spec/integration/rails/hash_with_indifferent_access_spec.rb +1 -1
- data/spec/integration/rspec/be_predicate_matcher_spec.rb +111 -59
- data/spec/integration/rspec/eq_matcher_spec.rb +1 -1
- data/spec/integration/rspec/have_predicate_matcher_spec.rb +484 -0
- data/spec/integration/rspec/match_array_matcher_spec.rb +372 -0
- data/spec/integration/rspec/match_matcher_spec.rb +8 -8
- data/spec/integration/rspec/raise_error_matcher_spec.rb +605 -226
- data/spec/integration/rspec/third_party_matcher_spec.rb +241 -0
- data/spec/integration/rspec/unhandled_errors_spec.rb +56 -81
- data/spec/spec_helper.rb +18 -7
- data/spec/support/integration/helpers.rb +10 -2
- data/spec/support/integration/matchers.rb +143 -0
- data/spec/support/models/active_record/query.rb +15 -0
- data/spec/support/object_id.rb +26 -0
- data/spec/support/ruby_versions.rb +4 -0
- data/spec/support/shared_examples/active_record.rb +71 -0
- data/spec/unit/equality_matcher_spec.rb +8 -8
- data/spec/unit/object_inspection_spec.rb +17 -17
- data/spec/unit/rspec/matchers/have_predicate_spec.rb +21 -0
- data/spec/unit/rspec/matchers/match_array_spec.rb +11 -0
- data/super_diff.gemspec +0 -1
- metadata +30 -34
- data/lib/super_diff/rspec/object_inspection/inspectors/partial_object.rb +0 -21
- data/spec/examples.txt +0 -350
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8efa30260e2d32c10ea6571d37a393756b216c1ba2c991d28a4124a0822c7e6f
|
4
|
+
data.tar.gz: a98a146c39eda8aeb3735869ffadacb279c26b76f2bf3f4b2ebc212fd6e8dbe1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0fdf3017f5a38865bb8cfbb15dfacf3a070f42c23883a6821b39a4b2bb00da3c9beb1e65c417b5094693ab14de18edf9934f23c7f242849cc2dfb950ee60649
|
7
|
+
data.tar.gz: 6484896862126281d2f051d7ef17b760426083bfba3f9ba7f93936f331dca3cee187cbd8e75e46e6a9f86cbcd17d38e47fd9c2096a7ffdb6dc4290bed763c92f
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
SuperDiff is a gem that hooks into RSpec to intelligently display the
|
11
11
|
differences between two data structures of any type.
|
12
12
|
|
13
|
-
📢 **[See what's changed in the latest version (0.
|
13
|
+
📢 **[See what's changed in the latest version (0.3.0)][changelog].**
|
14
14
|
|
15
15
|
[changelog]: CHANGELOG.md
|
16
16
|
|
@@ -84,13 +84,13 @@ expect(actual).to eq(expected)
|
|
84
84
|
|
85
85
|
You would get output that looks like this:
|
86
86
|
|
87
|
-

|
88
88
|
|
89
89
|
What this library does is to provide a diff engine that knows how to figure out
|
90
90
|
the differences between any two data structures and display them in a sensible
|
91
91
|
way. So, using the example above, you'd get this instead:
|
92
92
|
|
93
|
-

|
94
94
|
|
95
95
|
## Installation
|
96
96
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# rubocop:disable Style/BracesAroundHashParameters, Style/ClassAndModuleChildren
|
2
|
+
class ActiveRecord::Base
|
3
|
+
def attributes_for_super_diff
|
4
|
+
(attributes.keys.sort - ["id"]).reduce({ id: id }) do |hash, key|
|
5
|
+
hash.merge(key.to_sym => attributes[key])
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
# rubocop:enable Style/BracesAroundHashParameters, Style/ClassAndModuleChildren
|
data/lib/super_diff/csi.rb
CHANGED
@@ -36,6 +36,10 @@ module SuperDiff
|
|
36
36
|
text.gsub(/\e\[\d+(?:;\d+)*m(.+?)\e\[0m/, '\1')
|
37
37
|
end
|
38
38
|
|
39
|
+
def self.already_colorized?(text)
|
40
|
+
text.match?(/\e\[\d+m/)
|
41
|
+
end
|
42
|
+
|
39
43
|
def self.inspect_colors_in(text)
|
40
44
|
[FourBitColor, EightBitColor, TwentyFourBitColor].
|
41
45
|
reduce(text) do |str, klass|
|
@@ -6,6 +6,20 @@ module SuperDiff
|
|
6
6
|
raise NotImplementedError
|
7
7
|
end
|
8
8
|
# rubocop:enable Lint/UnusedMethodArgument
|
9
|
+
|
10
|
+
def pretty_print(pp)
|
11
|
+
pp.text "#{self.class.name}.new(["
|
12
|
+
pp.group_sub do
|
13
|
+
pp.nest(2) do
|
14
|
+
pp.breakable
|
15
|
+
pp.seplist(self) do |value|
|
16
|
+
pp.pp value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
pp.breakable
|
21
|
+
pp.text("])")
|
22
|
+
end
|
9
23
|
end
|
10
24
|
end
|
11
25
|
end
|
data/lib/super_diff/rspec.rb
CHANGED
@@ -25,30 +25,30 @@ module SuperDiff
|
|
25
25
|
@_configuration ||= Configuration.new
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.
|
29
|
-
|
28
|
+
def self.a_hash_including_something?(value)
|
29
|
+
fuzzy_object?(value) &&
|
30
30
|
value.respond_to?(:expecteds) &&
|
31
31
|
value.expecteds.one? &&
|
32
32
|
value.expecteds.first.is_a?(::Hash)
|
33
33
|
end
|
34
34
|
|
35
|
-
def self.
|
36
|
-
|
35
|
+
def self.a_collection_including_something?(value)
|
36
|
+
fuzzy_object?(value) &&
|
37
37
|
value.respond_to?(:expecteds) &&
|
38
38
|
!(value.expecteds.one? && value.expecteds.first.is_a?(::Hash))
|
39
39
|
end
|
40
40
|
|
41
|
-
def self.
|
42
|
-
|
41
|
+
def self.an_object_having_some_attributes?(value)
|
42
|
+
fuzzy_object?(value) &&
|
43
43
|
value.base_matcher.is_a?(::RSpec::Matchers::BuiltIn::HaveAttributes)
|
44
44
|
end
|
45
45
|
|
46
|
-
def self.
|
47
|
-
|
46
|
+
def self.a_collection_containing_exactly_something?(value)
|
47
|
+
fuzzy_object?(value) &&
|
48
48
|
value.base_matcher.is_a?(::RSpec::Matchers::BuiltIn::ContainExactly)
|
49
49
|
end
|
50
50
|
|
51
|
-
def self.
|
51
|
+
def self.fuzzy_object?(value)
|
52
52
|
value.is_a?(::RSpec::Matchers::AliasedMatcher)
|
53
53
|
end
|
54
54
|
end
|
@@ -14,16 +14,16 @@ module SuperDiff
|
|
14
14
|
extra_classes: [
|
15
15
|
*RSpec.configuration.extra_differ_classes,
|
16
16
|
Differs::CollectionContainingExactly,
|
17
|
-
Differs::
|
18
|
-
Differs::
|
19
|
-
Differs::
|
17
|
+
Differs::CollectionIncluding,
|
18
|
+
Differs::HashIncluding,
|
19
|
+
Differs::ObjectHavingAttributes,
|
20
20
|
],
|
21
21
|
extra_operational_sequencer_classes: [
|
22
22
|
*RSpec.configuration.extra_operational_sequencer_classes,
|
23
23
|
OperationalSequencers::CollectionContainingExactly,
|
24
|
-
OperationalSequencers::
|
25
|
-
OperationalSequencers::
|
26
|
-
OperationalSequencers::
|
24
|
+
OperationalSequencers::CollectionIncluding,
|
25
|
+
OperationalSequencers::HashIncluding,
|
26
|
+
OperationalSequencers::ObjectHavingAttributes,
|
27
27
|
],
|
28
28
|
extra_diff_formatter_classes: RSpec.configuration.extra_diff_formatter_classes,
|
29
29
|
)
|
@@ -5,9 +5,15 @@ module SuperDiff
|
|
5
5
|
:CollectionContainingExactly,
|
6
6
|
"super_diff/rspec/differs/collection_containing_exactly",
|
7
7
|
)
|
8
|
-
autoload
|
9
|
-
|
10
|
-
|
8
|
+
autoload(
|
9
|
+
:CollectionIncluding,
|
10
|
+
"super_diff/rspec/differs/collection_including",
|
11
|
+
)
|
12
|
+
autoload :HashIncluding, "super_diff/rspec/differs/hash_including"
|
13
|
+
autoload(
|
14
|
+
:ObjectHavingAttributes,
|
15
|
+
"super_diff/rspec/differs/object_having_attributes",
|
16
|
+
)
|
11
17
|
end
|
12
18
|
end
|
13
19
|
end
|
@@ -3,7 +3,7 @@ module SuperDiff
|
|
3
3
|
module Differs
|
4
4
|
class CollectionContainingExactly < SuperDiff::Differs::Array
|
5
5
|
def self.applies_to?(expected, actual)
|
6
|
-
SuperDiff::RSpec.
|
6
|
+
SuperDiff::RSpec.a_collection_containing_exactly_something?(expected) &&
|
7
7
|
actual.is_a?(::Array)
|
8
8
|
end
|
9
9
|
|
@@ -1,15 +1,16 @@
|
|
1
1
|
module SuperDiff
|
2
2
|
module RSpec
|
3
3
|
module Differs
|
4
|
-
class
|
4
|
+
class CollectionIncluding < SuperDiff::Differs::Array
|
5
5
|
def self.applies_to?(expected, actual)
|
6
|
-
SuperDiff::RSpec.
|
6
|
+
SuperDiff::RSpec.a_collection_including_something?(expected) &&
|
7
|
+
actual.is_a?(::Array)
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def operations
|
12
|
-
OperationalSequencers::
|
13
|
+
OperationalSequencers::CollectionIncluding.call(
|
13
14
|
expected: expected,
|
14
15
|
actual: actual,
|
15
16
|
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
|
@@ -1,15 +1,16 @@
|
|
1
1
|
module SuperDiff
|
2
2
|
module RSpec
|
3
3
|
module Differs
|
4
|
-
class
|
4
|
+
class HashIncluding < SuperDiff::Differs::Hash
|
5
5
|
def self.applies_to?(expected, actual)
|
6
|
-
SuperDiff::RSpec.
|
6
|
+
SuperDiff::RSpec.a_hash_including_something?(expected) &&
|
7
|
+
actual.is_a?(::Hash)
|
7
8
|
end
|
8
9
|
|
9
10
|
private
|
10
11
|
|
11
12
|
def operations
|
12
|
-
OperationalSequencers::
|
13
|
+
OperationalSequencers::HashIncluding.call(
|
13
14
|
expected: expected,
|
14
15
|
actual: actual,
|
15
16
|
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module SuperDiff
|
2
2
|
module RSpec
|
3
3
|
module Differs
|
4
|
-
class
|
4
|
+
class ObjectHavingAttributes < SuperDiff::Differs::DefaultObject
|
5
5
|
def self.applies_to?(expected, _actual)
|
6
|
-
SuperDiff::RSpec.
|
6
|
+
SuperDiff::RSpec.an_object_having_some_attributes?(expected)
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def operations
|
12
|
-
OperationalSequencers::
|
12
|
+
OperationalSequencers::ObjectHavingAttributes.call(
|
13
13
|
expected: expected,
|
14
14
|
actual: actual,
|
15
15
|
extra_operational_sequencer_classes: extra_operational_sequencer_classes,
|
@@ -10,6 +10,10 @@ module SuperDiff
|
|
10
10
|
:ContainExactly,
|
11
11
|
"super_diff/rspec/matcher_text_builders/contain_exactly",
|
12
12
|
)
|
13
|
+
autoload(
|
14
|
+
:HavePredicate,
|
15
|
+
"super_diff/rspec/matcher_text_builders/have_predicate",
|
16
|
+
)
|
13
17
|
autoload :Match, "super_diff/rspec/matcher_text_builders/match"
|
14
18
|
autoload(
|
15
19
|
:RaiseError,
|
@@ -36,27 +36,46 @@ module SuperDiff
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
39
|
+
def add_expected_value_to_failure_message(template)
|
40
40
|
template.add_text " "
|
41
|
-
template.add_text_in_color(
|
41
|
+
template.add_text_in_color(
|
42
|
+
alpha_color,
|
43
|
+
"#{expected_for_failure_message}?",
|
44
|
+
)
|
42
45
|
template.add_text " or "
|
43
|
-
template.add_text_in_color(
|
46
|
+
template.add_text_in_color(
|
47
|
+
alpha_color,
|
48
|
+
"#{expected_for_failure_message}s?",
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_expected_value_to_description(template)
|
53
|
+
template.add_text " "
|
54
|
+
template.add_text_in_color(
|
55
|
+
alpha_color,
|
56
|
+
"`#{expected_for_description}?`",
|
57
|
+
)
|
58
|
+
template.add_text " or "
|
59
|
+
template.add_text_in_color(
|
60
|
+
alpha_color,
|
61
|
+
"`#{expected_for_description}s?`",
|
62
|
+
)
|
44
63
|
end
|
45
64
|
|
46
65
|
def add_extra_after_error
|
47
66
|
if expected_predicate_method_name == :true?
|
48
67
|
template.add_text "\n\n"
|
49
68
|
template.add_text "(Perhaps you want to use "
|
50
|
-
template.add_text_in_color(:blue, "
|
69
|
+
template.add_text_in_color(:blue, "be(true)")
|
51
70
|
template.add_text " or "
|
52
|
-
template.add_text_in_color(:blue, "
|
71
|
+
template.add_text_in_color(:blue, "be_truthy")
|
53
72
|
template.add_text " instead?)"
|
54
73
|
elsif expected_predicate_method_name == :false?
|
55
74
|
template.add_text "\n\n"
|
56
75
|
template.add_text "(Perhaps you want to use "
|
57
|
-
template.add_text_in_color(:blue, "
|
76
|
+
template.add_text_in_color(:blue, "be(false)")
|
58
77
|
template.add_text " or "
|
59
|
-
template.add_text_in_color(:blue, "
|
78
|
+
template.add_text_in_color(:blue, "be_falsey")
|
60
79
|
template.add_text " instead?)"
|
61
80
|
end
|
62
81
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module SuperDiff
|
2
|
+
module RSpec
|
3
|
+
module MatcherTextBuilders
|
4
|
+
class HavePredicate < Base
|
5
|
+
def initialize(predicate_accessible:, private_predicate:, **rest)
|
6
|
+
super(**rest)
|
7
|
+
@predicate_accessible = predicate_accessible
|
8
|
+
@private_predicate = private_predicate
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def expected_action_for_failure_message
|
14
|
+
if predicate_accessible?
|
15
|
+
"return a truthy result for"
|
16
|
+
elsif private_predicate?
|
17
|
+
"have a public method"
|
18
|
+
else
|
19
|
+
"respond to"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def beta_color
|
24
|
+
:yellow
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_actual_value
|
28
|
+
template.add_text_in_color(beta_color) do
|
29
|
+
description_of(actual)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_expected_value_to_failure_message(template)
|
34
|
+
template.add_text " "
|
35
|
+
template.add_text_in_color(
|
36
|
+
alpha_color,
|
37
|
+
expected_for_failure_message,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_expected_value_to_description(template)
|
42
|
+
template.add_text " "
|
43
|
+
template.add_text_in_color(
|
44
|
+
alpha_color,
|
45
|
+
"`#{expected_for_description}`",
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def private_predicate?
|
52
|
+
@private_predicate
|
53
|
+
end
|
54
|
+
|
55
|
+
def predicate_accessible?
|
56
|
+
@predicate_accessible
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -5,7 +5,19 @@ module SuperDiff
|
|
5
5
|
protected
|
6
6
|
|
7
7
|
def actual_phrase
|
8
|
-
|
8
|
+
if actual
|
9
|
+
"Expected raised exception"
|
10
|
+
else
|
11
|
+
"Expected"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_actual_value
|
16
|
+
if actual
|
17
|
+
template.add_text_in_color(beta_color) { actual }
|
18
|
+
else
|
19
|
+
template.add_text("block")
|
20
|
+
end
|
9
21
|
end
|
10
22
|
end
|
11
23
|
end
|
@@ -93,19 +93,31 @@ module RSpec
|
|
93
93
|
if options.include?(:failure_lines)
|
94
94
|
@failure_line_groups = {
|
95
95
|
lines: options[:failure_lines],
|
96
|
-
|
96
|
+
already_colorized: false
|
97
97
|
}
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
# Override to only color uncolored lines in red
|
102
|
-
|
102
|
+
# and to not color empty lines
|
103
|
+
def colorized_message_lines(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
|
103
104
|
lines = failure_line_groups.flat_map do |group|
|
104
|
-
if group[:
|
105
|
+
if group[:already_colorized]
|
105
106
|
group[:lines]
|
106
107
|
else
|
107
108
|
group[:lines].map do |line|
|
108
|
-
|
109
|
+
if line.strip.empty?
|
110
|
+
line
|
111
|
+
else
|
112
|
+
indentation = line[/^[ ]+/]
|
113
|
+
rest = colorizer.wrap(line.sub(/^[ ]+/, ''), message_color)
|
114
|
+
|
115
|
+
if indentation
|
116
|
+
indentation + rest
|
117
|
+
else
|
118
|
+
rest
|
119
|
+
end
|
120
|
+
end
|
109
121
|
end
|
110
122
|
end
|
111
123
|
end
|
@@ -129,33 +141,68 @@ module RSpec
|
|
129
141
|
# Considering that `failure_slash_error_lines` is already colored,
|
130
142
|
# extract this from the other lines so that they, too, can be colored,
|
131
143
|
# later
|
144
|
+
#
|
145
|
+
# TODO: Refactor this somehow
|
146
|
+
#
|
132
147
|
def failure_line_groups
|
133
|
-
@failure_line_groups
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
148
|
+
if defined?(@failure_line_groups)
|
149
|
+
@failure_line_groups
|
150
|
+
else
|
151
|
+
@failure_line_groups = [
|
152
|
+
{
|
153
|
+
lines: failure_slash_error_lines,
|
154
|
+
already_colorized: true
|
155
|
+
}
|
156
|
+
]
|
138
157
|
|
139
158
|
sections = [failure_slash_error_lines, exception_lines]
|
140
159
|
separate_groups = (
|
141
160
|
sections.any? { |section| section.size > 1 } &&
|
142
161
|
!exception_lines.first.empty?
|
143
162
|
)
|
163
|
+
|
144
164
|
if separate_groups
|
145
|
-
|
165
|
+
@failure_line_groups << { lines: [''], already_colorized: true }
|
146
166
|
end
|
147
|
-
|
148
|
-
|
167
|
+
|
168
|
+
already_colorized = exception_lines.any? do |line|
|
169
|
+
SuperDiff::Csi.already_colorized?(line)
|
149
170
|
end
|
150
171
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
172
|
+
if already_colorized
|
173
|
+
@failure_line_groups << {
|
174
|
+
lines: exception_lines,
|
175
|
+
already_colorized: true
|
176
|
+
}
|
177
|
+
else
|
178
|
+
locatable_exception_lines =
|
179
|
+
exception_lines.each_with_index.map do |line, index|
|
180
|
+
{ text: line, index: index }
|
181
|
+
end
|
182
|
+
|
183
|
+
boundary_line =
|
184
|
+
locatable_exception_lines.find do |line, index|
|
185
|
+
line[:text].strip.empty? || line[:text].match?(/^ /)
|
186
|
+
end
|
187
|
+
|
188
|
+
if boundary_line
|
189
|
+
@failure_line_groups << {
|
190
|
+
lines: exception_lines[0..boundary_line[:index] - 1],
|
191
|
+
already_colorized: false
|
192
|
+
}
|
193
|
+
@failure_line_groups << {
|
194
|
+
lines: exception_lines[boundary_line[:index]..-1],
|
195
|
+
already_colorized: true
|
196
|
+
}
|
197
|
+
else
|
198
|
+
@failure_line_groups << {
|
199
|
+
lines: exception_lines,
|
200
|
+
already_colorized: false
|
201
|
+
}
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
@failure_line_groups
|
159
206
|
end
|
160
207
|
end
|
161
208
|
|
@@ -204,6 +251,11 @@ module RSpec
|
|
204
251
|
|
205
252
|
module Support
|
206
253
|
class ObjectFormatter
|
254
|
+
# Override to use our formatting algorithm
|
255
|
+
def self.format(value)
|
256
|
+
SuperDiff::ObjectInspection.inspect(value, as_single_line: true)
|
257
|
+
end
|
258
|
+
|
207
259
|
# Override to use our formatting algorithm
|
208
260
|
def format(value)
|
209
261
|
SuperDiff::ObjectInspection.inspect(value, as_single_line: true)
|
@@ -303,20 +355,6 @@ module RSpec
|
|
303
355
|
end)
|
304
356
|
end
|
305
357
|
|
306
|
-
class BeTruthy
|
307
|
-
prepend SuperDiff::RSpec::AugmentedMatcher
|
308
|
-
|
309
|
-
prepend(Module.new do
|
310
|
-
def expected_action_for_matcher_text
|
311
|
-
"be"
|
312
|
-
end
|
313
|
-
|
314
|
-
def expected_for_matcher_text
|
315
|
-
"truthy"
|
316
|
-
end
|
317
|
-
end)
|
318
|
-
end
|
319
|
-
|
320
358
|
class BeFalsey
|
321
359
|
prepend SuperDiff::RSpec::AugmentedMatcher
|
322
360
|
|
@@ -375,12 +413,18 @@ module RSpec
|
|
375
413
|
end)
|
376
414
|
end
|
377
415
|
|
378
|
-
class
|
416
|
+
class BeTruthy
|
379
417
|
prepend SuperDiff::RSpec::AugmentedMatcher
|
380
|
-
end
|
381
418
|
|
382
|
-
|
383
|
-
|
419
|
+
prepend(Module.new do
|
420
|
+
def expected_action_for_matcher_text
|
421
|
+
"be"
|
422
|
+
end
|
423
|
+
|
424
|
+
def expected_for_matcher_text
|
425
|
+
"truthy"
|
426
|
+
end
|
427
|
+
end)
|
384
428
|
end
|
385
429
|
|
386
430
|
class ContainExactly
|
@@ -405,72 +449,12 @@ module RSpec
|
|
405
449
|
end)
|
406
450
|
end
|
407
451
|
|
408
|
-
class
|
452
|
+
class Eq
|
409
453
|
prepend SuperDiff::RSpec::AugmentedMatcher
|
410
|
-
|
411
|
-
prepend(Module.new do
|
412
|
-
# Override this method so that the differ knows that this is a partial
|
413
|
-
# array or hash
|
414
|
-
def expected_for_diff
|
415
|
-
if expecteds.all? { |item| item.is_a?(Hash) }
|
416
|
-
matchers.a_collection_including(expecteds.first)
|
417
|
-
else
|
418
|
-
matchers.a_collection_including(*expecteds)
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
private
|
423
|
-
|
424
|
-
# Override to capitalize message and add period at end
|
425
|
-
def build_failure_message(negated:)
|
426
|
-
message = super
|
427
|
-
|
428
|
-
if actual.respond_to?(:include?)
|
429
|
-
message
|
430
|
-
elsif message.end_with?(".")
|
431
|
-
message.sub("\.$", ", ") + "but it does not respond to `include?`."
|
432
|
-
else
|
433
|
-
message + "\n\nBut it does not respond to `include?`."
|
434
|
-
end
|
435
|
-
end
|
436
|
-
|
437
|
-
# Override to use readable_list_of
|
438
|
-
def expected_for_description
|
439
|
-
readable_list_of(expecteds).lstrip
|
440
|
-
end
|
441
|
-
|
442
|
-
# Override to use readable_list_of
|
443
|
-
def expected_for_failure_message
|
444
|
-
# TODO: Switch to using @divergent_items and handle this in the text
|
445
|
-
# builder
|
446
|
-
readable_list_of(@divergent_items).lstrip
|
447
|
-
end
|
448
|
-
|
449
|
-
# Update to use (...) as delimiter instead of {...}
|
450
|
-
def readable_list_of(items)
|
451
|
-
if items && items.all? { |item| item.is_a?(Hash) }
|
452
|
-
description_of(items.inject(:merge)).
|
453
|
-
sub(/^\{ /, '(').
|
454
|
-
sub(/ \}$/, ')')
|
455
|
-
else
|
456
|
-
super
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end)
|
460
454
|
end
|
461
455
|
|
462
|
-
class
|
456
|
+
class Equal
|
463
457
|
prepend SuperDiff::RSpec::AugmentedMatcher
|
464
|
-
|
465
|
-
prepend(Module.new do
|
466
|
-
def matcher_text_builder_class
|
467
|
-
SuperDiff::RSpec::MatcherTextBuilders::Match
|
468
|
-
end
|
469
|
-
|
470
|
-
def matcher_text_builder_args
|
471
|
-
super.merge(expected_captures: @expected_captures)
|
472
|
-
end
|
473
|
-
end)
|
474
458
|
end
|
475
459
|
|
476
460
|
class HaveAttributes
|
@@ -550,33 +534,113 @@ module RSpec
|
|
550
534
|
end
|
551
535
|
end
|
552
536
|
|
553
|
-
class
|
537
|
+
class Has
|
554
538
|
prepend SuperDiff::RSpec::AugmentedMatcher
|
555
539
|
|
556
540
|
prepend(Module.new do
|
541
|
+
def actual_for_matcher_text
|
542
|
+
actual
|
543
|
+
end
|
544
|
+
|
545
|
+
def expected_for_matcher_text
|
546
|
+
"#{predicate}#{failure_message_args_description}"
|
547
|
+
end
|
548
|
+
|
549
|
+
def expected_action_for_matcher_text
|
550
|
+
"return true for"
|
551
|
+
end
|
552
|
+
|
557
553
|
def matcher_text_builder_class
|
558
|
-
SuperDiff::RSpec::MatcherTextBuilders::
|
554
|
+
SuperDiff::RSpec::MatcherTextBuilders::HavePredicate
|
559
555
|
end
|
560
556
|
|
561
557
|
def matcher_text_builder_args
|
562
558
|
super.merge(
|
563
|
-
|
564
|
-
|
565
|
-
expected_keywords: @expected_keywords,
|
566
|
-
unlimited_arguments: @unlimited_arguments
|
559
|
+
predicate_accessible: predicate_accessible?,
|
560
|
+
private_predicate: private_predicate?
|
567
561
|
)
|
568
562
|
end
|
563
|
+
end)
|
564
|
+
end
|
569
565
|
|
566
|
+
class Include
|
567
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
568
|
+
|
569
|
+
prepend(Module.new do
|
570
|
+
# Override this method so that the differ knows that this is a partial
|
571
|
+
# array or hash
|
572
|
+
def expected_for_diff
|
573
|
+
if expecteds.all? { |item| item.is_a?(Hash) }
|
574
|
+
matchers.a_collection_including(expecteds.first)
|
575
|
+
else
|
576
|
+
matchers.a_collection_including(*expecteds)
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
private
|
581
|
+
|
582
|
+
# Override to capitalize message and add period at end
|
583
|
+
def build_failure_message(negated:)
|
584
|
+
message = super
|
585
|
+
|
586
|
+
if actual.respond_to?(:include?)
|
587
|
+
message
|
588
|
+
elsif message.end_with?(".")
|
589
|
+
message.sub("\.$", ", ") + "but it does not respond to `include?`."
|
590
|
+
else
|
591
|
+
message + "\n\nBut it does not respond to `include?`."
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
# Override to use readable_list_of
|
570
596
|
def expected_for_description
|
571
|
-
|
597
|
+
readable_list_of(expecteds).lstrip
|
572
598
|
end
|
573
599
|
|
600
|
+
# Override to use readable_list_of
|
574
601
|
def expected_for_failure_message
|
575
|
-
@
|
602
|
+
# TODO: Switch to using @divergent_items and handle this in the text
|
603
|
+
# builder
|
604
|
+
readable_list_of(@divergent_items).lstrip
|
605
|
+
end
|
606
|
+
|
607
|
+
# Update to use (...) as delimiter instead of {...}
|
608
|
+
def readable_list_of(items)
|
609
|
+
if items && items.all? { |item| item.is_a?(Hash) }
|
610
|
+
description_of(items.inject(:merge)).
|
611
|
+
sub(/^\{ /, '(').
|
612
|
+
sub(/ \}$/, ')')
|
613
|
+
else
|
614
|
+
super
|
615
|
+
end
|
576
616
|
end
|
577
617
|
end)
|
578
618
|
end
|
579
619
|
|
620
|
+
class Match
|
621
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
622
|
+
|
623
|
+
prepend(Module.new do
|
624
|
+
def matcher_text_builder_class
|
625
|
+
SuperDiff::RSpec::MatcherTextBuilders::Match
|
626
|
+
end
|
627
|
+
|
628
|
+
def matcher_text_builder_args
|
629
|
+
super.merge(expected_captures: @expected_captures)
|
630
|
+
end
|
631
|
+
end)
|
632
|
+
end
|
633
|
+
|
634
|
+
class MatchArray < ContainExactly
|
635
|
+
def expected_for_diff
|
636
|
+
matchers.an_array_matching(expected)
|
637
|
+
end
|
638
|
+
|
639
|
+
def expected_action_for_matcher_text
|
640
|
+
"match array with"
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
580
644
|
class RaiseError
|
581
645
|
prepend SuperDiff::RSpec::AugmentedMatcher
|
582
646
|
|
@@ -588,7 +652,9 @@ module RSpec
|
|
588
652
|
end
|
589
653
|
|
590
654
|
def actual_for_diff
|
591
|
-
@actual_error
|
655
|
+
if @actual_error
|
656
|
+
@actual_error.message
|
657
|
+
end
|
592
658
|
end
|
593
659
|
|
594
660
|
def expected_for_matcher_text
|
@@ -608,7 +674,11 @@ module RSpec
|
|
608
674
|
end
|
609
675
|
|
610
676
|
def expected_action_for_failure_message
|
611
|
-
|
677
|
+
if @actual_error
|
678
|
+
"match"
|
679
|
+
else
|
680
|
+
"raise error"
|
681
|
+
end
|
612
682
|
end
|
613
683
|
|
614
684
|
def matcher_text_builder_class
|
@@ -617,9 +687,46 @@ module RSpec
|
|
617
687
|
end)
|
618
688
|
|
619
689
|
def self.matcher_name
|
620
|
-
|
690
|
+
"raise error"
|
621
691
|
end
|
622
692
|
end
|
693
|
+
|
694
|
+
class RespondTo
|
695
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
696
|
+
|
697
|
+
prepend(Module.new do
|
698
|
+
def initialize(*)
|
699
|
+
super
|
700
|
+
@failing_method_names = nil
|
701
|
+
end
|
702
|
+
|
703
|
+
def matcher_text_builder_class
|
704
|
+
SuperDiff::RSpec::MatcherTextBuilders::RespondTo
|
705
|
+
end
|
706
|
+
|
707
|
+
def matcher_text_builder_args
|
708
|
+
super.merge(
|
709
|
+
expected_arity: @expected_arity,
|
710
|
+
arbitrary_keywords: @arbitrary_keywords,
|
711
|
+
expected_keywords: @expected_keywords,
|
712
|
+
unlimited_arguments: @unlimited_arguments
|
713
|
+
)
|
714
|
+
end
|
715
|
+
|
716
|
+
def expected_for_description
|
717
|
+
@names
|
718
|
+
end
|
719
|
+
|
720
|
+
def expected_for_failure_message
|
721
|
+
@failing_method_names
|
722
|
+
end
|
723
|
+
end)
|
724
|
+
end
|
725
|
+
end
|
726
|
+
|
727
|
+
def match_array(items)
|
728
|
+
BuiltIn::MatchArray.new(items)
|
623
729
|
end
|
730
|
+
alias_matcher :an_array_matching, :match_array
|
624
731
|
end
|
625
732
|
end
|