rspec-resembles_json_matchers 0.7.2 → 0.9.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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +155 -0
- data/.travis.yml +5 -6
- data/Appraisals +7 -5
- data/Changelog.md +16 -0
- data/Gemfile +3 -1
- data/Guardfile +6 -5
- data/LICENSE.txt +13 -0
- data/README.md +5 -0
- data/Rakefile +2 -0
- data/examples/example_spec.rb +67 -63
- data/gemfiles/.bundle/config +5 -0
- data/gemfiles/rails_5.gemfile +2 -2
- data/gemfiles/rails_5.gemfile.lock +100 -67
- data/gemfiles/{rails_42.gemfile → rails_6.gemfile} +3 -3
- data/gemfiles/rails_6.gemfile.lock +236 -0
- data/lib/rspec/resembles_json_matchers.rb +16 -15
- data/lib/rspec/resembles_json_matchers/attribute_differ.rb +75 -55
- data/lib/rspec/resembles_json_matchers/attribute_matcher.rb +38 -18
- data/lib/rspec/resembles_json_matchers/helpers.rb +4 -3
- data/lib/rspec/resembles_json_matchers/json_matcher.rb +22 -33
- data/lib/rspec/resembles_json_matchers/matcherizer.rb +2 -3
- data/lib/rspec/resembles_json_matchers/resembles_any_of_matcher.rb +16 -15
- data/lib/rspec/resembles_json_matchers/resembles_array_matcher.rb +2 -4
- data/lib/rspec/resembles_json_matchers/resembles_boolean_matcher.rb +4 -1
- data/lib/rspec/resembles_json_matchers/resembles_class_matcher.rb +2 -1
- data/lib/rspec/resembles_json_matchers/resembles_date_matcher.rb +2 -0
- data/lib/rspec/resembles_json_matchers/resembles_hash_matcher.rb +11 -11
- data/lib/rspec/resembles_json_matchers/resembles_matcher.rb +8 -16
- data/lib/rspec/resembles_json_matchers/resembles_nil_matcher.rb +1 -0
- data/lib/rspec/resembles_json_matchers/resembles_numeric_matcher.rb +2 -1
- data/lib/rspec/resembles_json_matchers/resembles_route_matcher.rb +6 -3
- data/lib/rspec/resembles_json_matchers/resembles_string_matcher.rb +1 -0
- data/lib/rspec/resembles_json_matchers/string_indent.rb +4 -2
- data/lib/rspec/resembles_json_matchers/version.rb +3 -1
- data/rspec-resembles_json_matchers.gemspec +14 -9
- metadata +68 -24
- data/gemfiles/rails_42.gemfile.lock +0 -183
@@ -1,20 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "rspec/resembles_json_matchers/version"
|
2
4
|
require "rspec/resembles_json_matchers/string_indent"
|
3
5
|
|
4
6
|
module RSpec
|
5
7
|
module ResemblesJsonMatchers
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
require "rspec/resembles_json_matchers/helpers"
|
9
|
+
require "rspec/resembles_json_matchers/attribute_matcher"
|
10
|
+
require "rspec/resembles_json_matchers/json_matcher"
|
11
|
+
|
12
|
+
require "rspec/resembles_json_matchers/resembles_any_of_matcher"
|
13
|
+
require "rspec/resembles_json_matchers/resembles_route_matcher"
|
14
|
+
require "rspec/resembles_json_matchers/resembles_date_matcher"
|
15
|
+
require "rspec/resembles_json_matchers/resembles_numeric_matcher"
|
16
|
+
require "rspec/resembles_json_matchers/resembles_string_matcher"
|
17
|
+
require "rspec/resembles_json_matchers/resembles_boolean_matcher"
|
18
|
+
require "rspec/resembles_json_matchers/resembles_nil_matcher"
|
19
|
+
require "rspec/resembles_json_matchers/resembles_class_matcher"
|
18
20
|
|
19
21
|
def iso8601_timestamp
|
20
22
|
match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/)
|
@@ -32,7 +34,7 @@ module RSpec
|
|
32
34
|
|
33
35
|
def self.resembles_matcher_candidates
|
34
36
|
# Order matters
|
35
|
-
@
|
37
|
+
@resembles_matcher_candidates ||= [
|
36
38
|
JsonMatcher,
|
37
39
|
ResemblesAnyOfMatcher,
|
38
40
|
ResemblesRouteMatcher,
|
@@ -45,9 +47,8 @@ module RSpec
|
|
45
47
|
].freeze
|
46
48
|
end
|
47
49
|
|
48
|
-
def self.resembles_matcher_for(expected, **
|
50
|
+
def self.resembles_matcher_for(expected, **_a)
|
49
51
|
resembles_matcher_candidates.detect { |candidate| candidate.can_match?(expected) } || RSpec::Matchers::BuiltIn::Eq
|
50
52
|
end
|
51
|
-
|
52
53
|
end
|
53
54
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/inflector"
|
2
4
|
|
3
5
|
module RSpec::ResemblesJsonMatchers
|
@@ -47,59 +49,70 @@ module RSpec::ResemblesJsonMatchers
|
|
47
49
|
@buffer.print NORMAL_COLOR
|
48
50
|
@buffer.print prefix + " " + "#{matcher.attribute_name.to_json}: "
|
49
51
|
render(matcher.value_matcher, prefix: prefix + " ")
|
50
|
-
|
51
|
-
@buffer.
|
52
|
+
elsif nested_matcher?(matcher.value_matcher)
|
53
|
+
@buffer.print NORMAL_COLOR
|
54
|
+
@buffer.print prefix + " " + "#{matcher.attribute_name.to_json}: "
|
55
|
+
render(matcher.value_matcher, prefix: prefix + " ")
|
52
56
|
else
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
@buffer.print prefix + "#{matcher.attribute_name.to_json}: "
|
58
|
-
render(matcher.value_matcher, prefix: prefix)
|
59
|
-
@buffer.print(",") unless last
|
60
|
-
@buffer.puts
|
61
|
-
else
|
62
|
-
@buffer.print NORMAL_COLOR
|
63
|
-
@buffer.print prefix + " " + "#{matcher.attribute_name.to_json}: "
|
64
|
-
render(matcher.value_matcher, prefix: prefix + " ")
|
65
|
-
@buffer.print(",") unless last
|
66
|
-
@buffer.puts
|
67
|
-
end
|
57
|
+
@buffer.print REMOVED_COLOR
|
58
|
+
@buffer.print prefix
|
59
|
+
if prefix.include? "-"
|
60
|
+
@buffer.print " "
|
68
61
|
else
|
69
|
-
@buffer.print
|
70
|
-
@buffer.print prefix
|
71
|
-
if prefix.include? "-"
|
72
|
-
@buffer.print " "
|
73
|
-
else
|
74
|
-
@buffer.print "- "
|
75
|
-
end
|
76
|
-
@buffer.print "#{matcher.attribute_name.to_json}: "
|
77
|
-
render(matcher.value_matcher, prefix: prefix + " ")
|
78
|
-
@buffer.print NORMAL_COLOR
|
79
|
-
@buffer.print(",") unless last
|
80
|
-
@buffer.puts
|
81
|
-
unless matcher.missing_attribute?
|
82
|
-
@buffer.print ADDED_COLOR
|
83
|
-
@buffer.print prefix + "+ #{matcher.attribute_name.to_json}: "
|
84
|
-
render(matcher.actual_value, prefix: prefix + " ")
|
85
|
-
@buffer.print NORMAL_COLOR
|
86
|
-
@buffer.print(",") unless last
|
87
|
-
@buffer.puts
|
88
|
-
end
|
62
|
+
@buffer.print "- "
|
89
63
|
end
|
64
|
+
@buffer.print "#{matcher.attribute_name.to_json}: "
|
65
|
+
render(matcher.value_matcher, prefix: prefix + " ")
|
66
|
+
@buffer.print NORMAL_COLOR
|
67
|
+
@buffer.print(",") unless last
|
68
|
+
@buffer.puts
|
69
|
+
@buffer.print ADDED_COLOR
|
70
|
+
@buffer.print prefix + "+ #{matcher.attribute_name.to_json}: "
|
71
|
+
render(matcher.actual_value, prefix: prefix + " ")
|
72
|
+
@buffer.print NORMAL_COLOR
|
90
73
|
end
|
74
|
+
@buffer.print(",") unless last
|
75
|
+
@buffer.puts
|
76
|
+
end
|
77
|
+
|
78
|
+
def render_MissingAttributeMatcher(matcher, prefix: "", last: false)
|
79
|
+
prefix += (prefix.include?("-") ? " " : "- ")
|
80
|
+
@buffer.print REMOVED_COLOR
|
81
|
+
@buffer.print prefix + "#{matcher.attribute_name.to_json}: "
|
82
|
+
render(matcher.value_matcher, prefix: prefix)
|
83
|
+
@buffer.print(",") unless last
|
84
|
+
@buffer.puts
|
85
|
+
end
|
86
|
+
|
87
|
+
def render_ExtraAttributeMatcher(matcher, prefix: "", last: false)
|
88
|
+
prefix += "+ "
|
89
|
+
@buffer.print ADDED_COLOR
|
90
|
+
@buffer.print prefix + matcher.attribute_name.to_json + ": "
|
91
|
+
render(matcher.actual_value, prefix: prefix)
|
92
|
+
@buffer.print "," unless last
|
93
|
+
@buffer.puts
|
91
94
|
end
|
92
95
|
|
93
|
-
def render_ResemblesAnyOfMatcher(matcher, prefix: "", **
|
96
|
+
def render_ResemblesAnyOfMatcher(matcher, prefix: "", **_opts)
|
94
97
|
@buffer.puts "["
|
95
|
-
if matcher.
|
96
|
-
|
97
|
-
|
98
|
-
|
98
|
+
if matcher.matched?
|
99
|
+
matcher.original_expected.each do |item|
|
100
|
+
@buffer.print JSON.pretty_generate(item).indent(1, NORMAL_COLOR + prefix + "- ")
|
101
|
+
last = (matcher.original_expected.last == item)
|
102
|
+
@buffer.print(",") unless last
|
103
|
+
@buffer.puts
|
104
|
+
end
|
105
|
+
elsif matcher.actual.nil? || matcher.actual.empty?
|
106
|
+
matcher.expected.each do |expected_matcher|
|
107
|
+
render expected_matcher, prefix: prefix + " ", starts_on_newline: true
|
108
|
+
last = (matcher.expected.last == expected_matcher)
|
109
|
+
@buffer.print(",") unless last
|
110
|
+
@buffer.puts
|
111
|
+
end
|
99
112
|
else
|
100
113
|
matcher.attempted_matchers.each do |attempted_matcher|
|
101
|
-
last = (matcher.attempted_matchers.last == attempted_matcher)
|
102
114
|
render attempted_matcher, prefix: prefix + " ", starts_on_newline: true
|
115
|
+
last = (matcher.attempted_matchers.last == attempted_matcher)
|
103
116
|
@buffer.print(",") unless last
|
104
117
|
@buffer.puts
|
105
118
|
end
|
@@ -107,36 +120,45 @@ module RSpec::ResemblesJsonMatchers
|
|
107
120
|
@buffer.print prefix + "]"
|
108
121
|
end
|
109
122
|
|
110
|
-
def
|
123
|
+
def render_ResemblesBooleanMatcher(matcher, **_opts)
|
111
124
|
@buffer.print matcher.expected.to_json
|
112
125
|
end
|
113
126
|
|
114
|
-
def
|
127
|
+
def render_ResemblesStringMatcher(matcher, **_opts)
|
115
128
|
@buffer.print matcher.expected.to_json
|
116
129
|
end
|
117
130
|
|
118
|
-
def
|
131
|
+
def render_ResemblesDateMatcher(matcher, **_opts)
|
119
132
|
@buffer.print matcher.expected.to_json
|
120
133
|
end
|
121
134
|
|
122
|
-
def
|
135
|
+
def render_ResemblesNumericMatcher(matcher, **_opts)
|
136
|
+
@buffer.print matcher.expected.to_json
|
137
|
+
end
|
138
|
+
|
139
|
+
def render_ResemblesClassMatcher(matcher, **_opts)
|
123
140
|
@buffer.print matcher.expected.inspect
|
124
141
|
end
|
125
142
|
|
126
|
-
def render_ResemblesNilMatcher(
|
143
|
+
def render_ResemblesNilMatcher(_matcher, **_opts)
|
127
144
|
@buffer.print "null"
|
128
145
|
end
|
129
146
|
|
147
|
+
def render_ResemblesRouteMatcher(matcher, **_opts)
|
148
|
+
@buffer.print matcher.expected.inspect
|
149
|
+
end
|
150
|
+
|
130
151
|
def method_missing(method_name, *args, &block)
|
131
152
|
if method_name.to_s.start_with?("render_")
|
132
153
|
raise NoMethodError, method_name if method_name.to_s.end_with?("Matcher")
|
154
|
+
|
133
155
|
@buffer.print RSpec::Support::ObjectFormatter.format(args.first)
|
134
156
|
else
|
135
157
|
super
|
136
158
|
end
|
137
159
|
end
|
138
160
|
|
139
|
-
def respond_to_missing?(method_name,
|
161
|
+
def respond_to_missing?(method_name, _include_private = false)
|
140
162
|
method_name.to_s.start_with?("render_")
|
141
163
|
end
|
142
164
|
|
@@ -144,11 +166,9 @@ module RSpec::ResemblesJsonMatchers
|
|
144
166
|
matcher.is_a?(JsonMatcher) || matcher.is_a?(ResemblesAnyOfMatcher)
|
145
167
|
end
|
146
168
|
|
147
|
-
NORMAL_COLOR = "\e[0m"
|
148
|
-
REMOVED_COLOR = "\e[31m"
|
149
|
-
ADDED_COLOR = "\e[32m"
|
150
|
-
NEUTRAL_COLOR = "\e[34m"
|
151
|
-
|
169
|
+
NORMAL_COLOR = "\e[0m"
|
170
|
+
REMOVED_COLOR = "\e[31m" # Red
|
171
|
+
ADDED_COLOR = "\e[32m" # Green
|
172
|
+
NEUTRAL_COLOR = "\e[34m" # Blue
|
152
173
|
end
|
153
174
|
end
|
154
|
-
|
@@ -1,13 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/hash/indifferent_access"
|
4
|
+
require "active_support/core_ext/object/try"
|
2
5
|
|
3
6
|
module RSpec::ResemblesJsonMatchers
|
4
|
-
|
5
7
|
class AttributeMatcher
|
6
8
|
include RSpec::ResemblesJsonMatchers::Helpers
|
9
|
+
Undefined = Object.new # TODO use Dry::Core::Constants::Undefined
|
7
10
|
|
8
11
|
attr_reader :attribute_name, :expected, :document
|
9
12
|
|
10
|
-
def initialize(attribute_name, expected = NullMatcher)
|
13
|
+
def initialize(attribute_name, expected = NullMatcher.new)
|
11
14
|
@attribute_name, @expected = attribute_name, expected
|
12
15
|
end
|
13
16
|
|
@@ -16,17 +19,13 @@ module RSpec::ResemblesJsonMatchers
|
|
16
19
|
end
|
17
20
|
|
18
21
|
def matches?(document)
|
19
|
-
@document = document.with_indifferent_access
|
22
|
+
@document = document.try(:with_indifferent_access)
|
20
23
|
|
21
|
-
@matched =
|
24
|
+
@matched = document.key?(attribute_name) && expected.matches?(actual_value)
|
22
25
|
end
|
23
26
|
|
24
27
|
def failure_message
|
25
|
-
|
26
|
-
%{Expected document to have attribute #{attribute_name.inspect}}
|
27
|
-
else
|
28
|
-
%{Expected attribute #{attribute_name.inspect} to #{value_matcher.description}, but it was #{actual_value.inspect}}
|
29
|
-
end
|
28
|
+
%{Expected attribute #{attribute_name.inspect} to #{value_matcher.description}, but it was #{actual_value.inspect}}
|
30
29
|
end
|
31
30
|
|
32
31
|
def matched?
|
@@ -45,14 +44,6 @@ module RSpec::ResemblesJsonMatchers
|
|
45
44
|
document.fetch(attribute_name, nil)
|
46
45
|
end
|
47
46
|
|
48
|
-
def missing_attribute?
|
49
|
-
!has_attribute?
|
50
|
-
end
|
51
|
-
|
52
|
-
def has_attribute?
|
53
|
-
document && document.key?(attribute_name)
|
54
|
-
end
|
55
|
-
|
56
47
|
NullMatcher = Class.new do
|
57
48
|
def matches?(*_args)
|
58
49
|
true
|
@@ -70,7 +61,36 @@ module RSpec::ResemblesJsonMatchers
|
|
70
61
|
def ===(_other)
|
71
62
|
true
|
72
63
|
end
|
73
|
-
end
|
64
|
+
end
|
65
|
+
end
|
74
66
|
|
67
|
+
class MissingAttributeMatcher < AttributeMatcher
|
68
|
+
def matches?(document)
|
69
|
+
@document = document.try(:with_indifferent_access)
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def failure_message
|
74
|
+
"Document had is missing attribute #{attribute_name.inspect}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def description
|
78
|
+
"be present"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class ExtraAttributeMatcher < AttributeMatcher
|
83
|
+
def matches?(document)
|
84
|
+
@document = document.try(:with_indifferent_access)
|
85
|
+
false
|
86
|
+
end
|
87
|
+
|
88
|
+
def failure_message
|
89
|
+
"Document had unexpected attribute #{attribute_name.inspect}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def description
|
93
|
+
"not be present"
|
94
|
+
end
|
75
95
|
end
|
76
96
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
module RSpec::ResemblesJsonMatchers
|
@@ -14,16 +16,15 @@ module RSpec::ResemblesJsonMatchers
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def matcherize(expected)
|
17
|
-
if
|
19
|
+
if matcher?(expected)
|
18
20
|
expected
|
19
21
|
else
|
20
22
|
RSpec::ResemblesJsonMatchers.resembles_matcher_for(expected).new(expected)
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
26
|
+
def matcher?(obj)
|
25
27
|
obj.respond_to?(:matches?) && obj.respond_to?(:description)
|
26
28
|
end
|
27
|
-
|
28
29
|
end
|
29
30
|
end
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "active_support/core_ext/hash/keys" # stringify_keys
|
2
4
|
require "json"
|
3
5
|
|
6
|
+
require "rspec/matchers"
|
4
7
|
require "rspec/resembles_json_matchers/attribute_differ"
|
5
8
|
|
6
9
|
module RSpec::ResemblesJsonMatchers
|
@@ -12,17 +15,18 @@ module RSpec::ResemblesJsonMatchers
|
|
12
15
|
hash.is_a? Hash
|
13
16
|
end
|
14
17
|
|
15
|
-
attr_reader :expected
|
18
|
+
attr_reader :expected
|
16
19
|
|
17
20
|
def initialize(expected_json)
|
18
|
-
@expected = expected_json.deep_stringify_keys
|
21
|
+
@expected = expected_json.try(:deep_stringify_keys)
|
19
22
|
end
|
20
23
|
|
21
24
|
def matches?(actual_json)
|
22
|
-
@actual = actual_json.deep_stringify_keys
|
25
|
+
@actual = actual_json.try(:deep_stringify_keys)
|
26
|
+
# Can't use #all? because it stops on the first false
|
23
27
|
all_passed = true
|
24
|
-
expected_matchers.each do |
|
25
|
-
result =
|
28
|
+
expected_matchers.each do |_key, matcher|
|
29
|
+
result = matcher.matches?(actual)
|
26
30
|
all_passed &&= result
|
27
31
|
end
|
28
32
|
all_passed
|
@@ -37,49 +41,34 @@ module RSpec::ResemblesJsonMatchers
|
|
37
41
|
AttributeDiffer.new(self).to_s
|
38
42
|
end
|
39
43
|
|
40
|
-
def to_json
|
44
|
+
def to_json(*_args)
|
41
45
|
failure_message
|
42
46
|
end
|
43
47
|
|
44
48
|
def expected_matchers
|
45
49
|
@expected_matchers ||= {}.tap do |hsh|
|
46
|
-
expected.each do |
|
47
|
-
|
50
|
+
(expected.keys + actual.keys).uniq.each do |key|
|
51
|
+
expected_value = matcherize(expected[key])
|
52
|
+
hsh[key.to_s] =
|
53
|
+
if !expected.key?(key) then ExtraAttributeMatcher.new(key, expected_value)
|
54
|
+
elsif !actual.key?(key) then MissingAttributeMatcher.new(key, expected_value)
|
55
|
+
else
|
56
|
+
AttributeMatcher.new(key, expected_value)
|
57
|
+
end
|
48
58
|
end
|
49
59
|
end
|
50
60
|
end
|
51
61
|
|
52
62
|
def expected_formatted
|
53
|
-
out = "{\n"
|
54
|
-
out << expected_matchers.map do |k,v|
|
63
|
+
out = +"{\n"
|
64
|
+
out << expected_matchers.map do |k, v|
|
55
65
|
%{"#{k}": #{RSpec::Support::ObjectFormatter.format(v.expected_value)}}.indent(2)
|
56
66
|
end.join(",\n")
|
57
67
|
out << "\n}"
|
58
68
|
end
|
59
69
|
|
60
|
-
def
|
61
|
-
|
62
|
-
case line.chr[0]
|
63
|
-
when "-" then red line
|
64
|
-
when "+" then green line
|
65
|
-
end
|
66
|
-
end.compact
|
67
|
-
end
|
68
|
-
|
69
|
-
def color(text, color_code)
|
70
|
-
"\e[#{color_code}m#{text}\e[0m"
|
71
|
-
end
|
72
|
-
|
73
|
-
def red(text)
|
74
|
-
color(text, 31)
|
75
|
-
end
|
76
|
-
|
77
|
-
def green(text)
|
78
|
-
color(text, 32)
|
79
|
-
end
|
80
|
-
|
81
|
-
def normal(text)
|
82
|
-
color(text, 0)
|
70
|
+
def actual
|
71
|
+
@actual ||= {}
|
83
72
|
end
|
84
73
|
end
|
85
74
|
end
|