super_diff 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![Before super_diff](doc/
|
87
|
+
![Before super_diff](doc/before.png)
|
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
|
-
![After super_diff](doc/
|
93
|
+
![After super_diff](doc/after.png)
|
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
|