rspec-json_matcher 0.0.6 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b01935d9caff916affc9015bb7210a04314b351
4
- data.tar.gz: f781b67128b9852ca4d5adbd4a603c07cc324568
3
+ metadata.gz: 8fdf55842f130209991f93fbcd8a241467e1a002
4
+ data.tar.gz: daf74c7fa6e9feb16f33efdc480b88138cc6d8f8
5
5
  SHA512:
6
- metadata.gz: 4981405b7a1833d0255d79b67aebea2cb05051f682f13492546905c766424528b35b5cd7a7770fcfa67e189f32587f5060cb276cb6215ae860e8892bdaa328df
7
- data.tar.gz: 3b073a2a714d677a3f787de3d77fefcd946511503f2b68ed8f359dfb3088ad440a5bad6e7e2496ba7875b88a6f524c33986a356cb9371a1f55b435c5d3ddd8f7
6
+ metadata.gz: 83705b7ed68482bbbd4d411c6dff881db6bdbf9922f53fe3dae3375323d9ab1fdd9c1617f06b35d119d07bb3d3e6601cf8fe2fe4781b5e2f7772034f1ba27689
7
+ data.tar.gz: 60942294a04c7df38dbfeaa382722f8d8f26f9e9ff58601b750feca501da15cbedb0ac8558843338c5afd66aae6e892cec6db4089674ab73e21b23dfa16399ee
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.1.0
2
+ * Change interface to be_json_including & be_json_as matchers
3
+
1
4
  ## 0.0.6
2
5
  * Fix a bug in comparison with Hash keys
3
6
 
data/README.md CHANGED
@@ -13,6 +13,17 @@ require "rspec/json_matcher"
13
13
  RSpec.configuration.include RSpec::JsonMatcher
14
14
  ```
15
15
 
16
+ ### Matchers
17
+ * be_json
18
+ * be_json_including
19
+ * be_json_as
20
+
21
+ ```ruby
22
+ { "a" => "b", "c" => "d" }.to_json.should be_json
23
+ { "a" => "b", "c" => "d" }.to_json.should be_json_including("a" => "b")
24
+ { "a" => "b", "c" => "d" }.to_json.should be_json_as("a" => "b", "c" => "d")
25
+ ```
26
+
16
27
  ### Example
17
28
  ```ruby
18
29
  [
@@ -42,7 +53,7 @@ RSpec.configuration.include RSpec::JsonMatcher
42
53
  "git_push_url" => "git@gist.github.com:1.git",
43
54
  "created_at" => "2010-04-14T02:15:15Z"
44
55
  }
45
- ].to_json.should be_json([
56
+ ].to_json.should be_json_as([
46
57
  {
47
58
  "url" => /^https:/,
48
59
  "id" => /^\d+$/,
@@ -1,120 +1,25 @@
1
1
  require "rspec/json_matcher/version"
2
+ require "rspec/json_matcher/abstract_comparer"
3
+ require "rspec/json_matcher/exact_comparer"
4
+ require "rspec/json_matcher/fuzzy_comparer"
5
+ require "rspec/json_matcher/abstract_matcher"
6
+ require "rspec/json_matcher/exact_matcher"
7
+ require "rspec/json_matcher/fuzzy_matcher"
2
8
  require "json"
3
9
  require "awesome_print"
4
10
 
5
11
  module RSpec
6
12
  module JsonMatcher
7
13
  def be_json(expected = nil)
8
- Matcher.new(expected)
14
+ ExactMatcher.new(expected)
9
15
  end
10
16
 
11
- class Matcher
12
- attr_reader :expected, :parsed
13
-
14
- def initialize(expected = nil)
15
- @expected = expected
16
- end
17
-
18
- def matches?(json)
19
- @parsed = JSON.parse(json)
20
- if has_expectation?
21
- Comparer.compare(parsed, expected)
22
- else
23
- true
24
- end
25
- rescue JSON::ParserError
26
- @parser_error = true
27
- false
28
- end
29
-
30
- def description
31
- "be JSON"
32
- end
33
-
34
- def failure_message_for_should
35
- if has_parser_error?
36
- "expected value to be parsed as JSON, but failed"
37
- else
38
- inspection
39
- end
40
- end
41
-
42
- def failure_message_for_should_not
43
- if has_parser_error?
44
- "expected value not to be parsed as JSON, but succeeded"
45
- else
46
- inspection("not ")
47
- end
48
- end
49
-
50
- private
51
-
52
- def has_parser_error?
53
- !!@parser_error
54
- end
55
-
56
- def has_expectation?
57
- !!expected
58
- end
59
-
60
- def inspection(prefix = nil)
61
- ["expected #{prefix}to match:", expected.ai(indent: -2), "", "actual:", parsed.ai(indent: -2)].join("\n")
62
- end
17
+ def be_json_as(expected)
18
+ ExactMatcher.new(expected)
63
19
  end
64
20
 
65
- class Comparer
66
- attr_reader :actual, :expected
67
-
68
- def self.compare(*args)
69
- new(*args).compare
70
- end
71
-
72
- def self.extract_keys(array_or_hash)
73
- if array_or_hash.is_a?(Array)
74
- array_or_hash.each_index.to_a
75
- else
76
- array_or_hash.keys
77
- end
78
- end
79
-
80
- def initialize(actual, expected)
81
- @actual = actual
82
- @expected = expected
83
- end
84
-
85
- def compare
86
- has_same_value? || has_same_collection?
87
- end
88
-
89
- private
90
-
91
- def has_same_class?
92
- actual.class == expected.class
93
- end
94
-
95
- def has_same_keys?
96
- self.class.extract_keys(actual).sort == self.class.extract_keys(expected).sort
97
- end
98
-
99
- def has_same_value?
100
- if expected.respond_to?(:call)
101
- expected.call(actual)
102
- else
103
- expected === actual
104
- end
105
- end
106
-
107
- def has_same_collection?
108
- collection? && has_same_class? && has_same_keys? && has_same_values?
109
- end
110
-
111
- def has_same_values?
112
- self.class.extract_keys(actual).all? {|key| self.class.compare(actual[key], expected[key]) }
113
- end
114
-
115
- def collection?
116
- actual.is_a?(Array) || actual.is_a?(Hash)
117
- end
21
+ def be_json_including(expected)
22
+ FuzzyMatcher.new(expected)
118
23
  end
119
24
  end
120
25
  end
@@ -0,0 +1,66 @@
1
+ module RSpec
2
+ module JsonMatcher
3
+ class AbstractComparer
4
+ attr_reader :actual, :expected
5
+
6
+ def self.compare(*args)
7
+ new(*args).compare
8
+ end
9
+
10
+ def self.extract_keys(array_or_hash)
11
+ if array_or_hash.is_a?(Array)
12
+ array_or_hash.each_index.to_a
13
+ else
14
+ array_or_hash.keys
15
+ end
16
+ end
17
+
18
+ def initialize(actual, expected)
19
+ @actual = actual
20
+ @expected = expected
21
+ end
22
+
23
+ def compare
24
+ has_same_value? || has_same_collection?
25
+ end
26
+
27
+ private
28
+
29
+ def has_same_class?
30
+ actual.class == expected.class
31
+ end
32
+
33
+ def has_same_keys?
34
+ self.class.extract_keys(actual).sort == self.class.extract_keys(expected).sort
35
+ end
36
+
37
+ def has_same_value?
38
+ if expected.respond_to?(:call)
39
+ expected.call(actual)
40
+ else
41
+ expected === actual
42
+ end
43
+ end
44
+
45
+ def has_same_collection?
46
+ raise NotImplementedError, "You must implement #{self.class}#has_same_collection?"
47
+ end
48
+
49
+ def has_same_values?
50
+ if expected.is_a?(Array)
51
+ expected.each_index.all? do |index|
52
+ index < actual.size && self.class.compare(actual[index], expected[index])
53
+ end
54
+ else
55
+ expected.keys.all? do |key|
56
+ actual.has_key?(key) && self.class.compare(actual[key], expected[key])
57
+ end
58
+ end
59
+ end
60
+
61
+ def collection?
62
+ actual.is_a?(Array) || actual.is_a?(Hash)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,61 @@
1
+ module RSpec
2
+ module JsonMatcher
3
+ class AbstractMatcher
4
+ attr_reader :expected, :parsed
5
+
6
+ def initialize(expected = nil)
7
+ @expected = expected
8
+ end
9
+
10
+ def matches?(json)
11
+ @parsed = JSON.parse(json)
12
+ if has_expectation?
13
+ compare
14
+ else
15
+ true
16
+ end
17
+ rescue JSON::ParserError
18
+ @parser_error = true
19
+ false
20
+ end
21
+
22
+ def compare
23
+ raise NotImplementedError, "You must implement #{self.class}#compare"
24
+ end
25
+
26
+ def description
27
+ "be JSON"
28
+ end
29
+
30
+ def failure_message_for_should
31
+ if has_parser_error?
32
+ "expected value to be parsed as JSON, but failed"
33
+ else
34
+ inspection
35
+ end
36
+ end
37
+
38
+ def failure_message_for_should_not
39
+ if has_parser_error?
40
+ "expected value not to be parsed as JSON, but succeeded"
41
+ else
42
+ inspection("not ")
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def has_parser_error?
49
+ !!@parser_error
50
+ end
51
+
52
+ def has_expectation?
53
+ !!expected
54
+ end
55
+
56
+ def inspection(prefix = nil)
57
+ ["expected #{prefix}to match:", expected.ai(indent: -2), "", "actual:", parsed.ai(indent: -2)].join("\n")
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ module RSpec
2
+ module JsonMatcher
3
+ class ExactComparer < AbstractComparer
4
+ private
5
+
6
+ def has_same_collection?
7
+ collection? && has_same_class? && has_same_keys? && has_same_values?
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module RSpec
2
+ module JsonMatcher
3
+ class ExactMatcher < AbstractMatcher
4
+ def compare
5
+ ExactComparer.compare(parsed, expected)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module RSpec
2
+ module JsonMatcher
3
+ class FuzzyComparer < AbstractComparer
4
+ private
5
+
6
+ def has_same_collection?
7
+ collection? && has_same_class? && has_same_values?
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module RSpec
2
+ module JsonMatcher
3
+ class FuzzyMatcher < AbstractMatcher
4
+ def compare
5
+ FuzzyComparer.compare(parsed, expected)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module JsonMatcher
3
- VERSION = "0.0.6"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -1,78 +1,279 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe RSpec::JsonMatcher do
4
- context "with invalid JSON" do
5
- it "does not match" do
6
- "".should_not be_json
4
+ describe "#be_json" do
5
+ context "with invalid JSON" do
6
+ it "does not match" do
7
+ "".should_not be_json
8
+ end
7
9
  end
8
- end
9
10
 
10
- context "with invalid keys JSON" do
11
- it "does not match" do
12
- {
13
- "a" => nil
14
- }.to_json.should_not be_json(
15
- "b" => nil
16
- )
11
+ context "with valid JSON" do
12
+ it "matches" do
13
+ {}.to_json.should be_json
14
+ end
17
15
  end
18
16
  end
19
17
 
20
- context "with non-existent keys in JSON" do
21
- it "does not match" do
22
- {
23
- "a" => nil,
24
- }.to_json.should_not be_json(
25
- "a" => nil,
26
- "b" => nil,
27
- )
18
+ describe "#be_json_as" do
19
+ context "with invalid JSON" do
20
+ it "does not match" do
21
+ "".should_not be_json_as("a" => "b")
22
+ end
23
+ end
24
+
25
+ context "with few keys" do
26
+ it "does not match" do
27
+ {
28
+ "a" => 1,
29
+ "b" => 2,
30
+ }.to_json.should_not be_json_as(
31
+ "a" => 1,
32
+ )
33
+ end
34
+ end
35
+
36
+ context "with too many keys" do
37
+ it "does not match" do
38
+ {
39
+ "a" => 1,
40
+ }.to_json.should_not be_json_as(
41
+ "a" => 1,
42
+ "b" => 2,
43
+ )
44
+ end
45
+ end
46
+
47
+ context "with different values" do
48
+ it "does not match" do
49
+ {
50
+ "a" => 1,
51
+ "b" => 2,
52
+ }.to_json.should_not be_json_as(
53
+ "a" => 2,
54
+ "b" => 2,
55
+ )
56
+ end
57
+ end
58
+
59
+ context "with same keys and values" do
60
+ it "matches" do
61
+ {
62
+ "a" => 1,
63
+ "b" => 2,
64
+ }.to_json.should be_json_as(
65
+ "a" => 1,
66
+ "b" => 2,
67
+ )
68
+ end
69
+ end
70
+
71
+ context "with nil values" do
72
+ it "does not match" do
73
+ {
74
+ "a" => nil,
75
+ }.to_json.should_not be_json_as(
76
+ "b" => nil,
77
+ )
78
+ end
79
+ end
80
+
81
+ context "with subset array" do
82
+ it "does not match" do
83
+ [
84
+ "a",
85
+ "b",
86
+ ].to_json.should_not be_json_as(
87
+ [
88
+ "a",
89
+ ],
90
+ )
91
+ end
92
+ end
93
+
94
+ context "with superset array" do
95
+ it "does not match" do
96
+ [
97
+ "a",
98
+ "b",
99
+ ].to_json.should_not be_json_as(
100
+ [
101
+ "a",
102
+ "b",
103
+ "c",
104
+ ],
105
+ )
106
+ end
107
+ end
108
+
109
+ context "with superset array with nil" do
110
+ it "does not match" do
111
+ [
112
+ "a",
113
+ "b",
114
+ ].to_json.should_not be_json_as(
115
+ [
116
+ "a",
117
+ "b",
118
+ nil,
119
+ ],
120
+ )
121
+ end
122
+ end
123
+
124
+ context "with complex JSON" do
125
+ it "matches" do
126
+ [
127
+ {
128
+ "url" => "https://api.github.com/gists/17a07d0a27fd3f708f5f",
129
+ "id" => "1",
130
+ "description" => "description of gist",
131
+ "public" => true,
132
+ "user" => {
133
+ "login" => "octocat",
134
+ "id" => 1,
135
+ "avatar_url" => "https://github.com/images/error/octocat_happy.gif",
136
+ "gravatar_id" => "somehexcode",
137
+ "url" => "https://api.github.com/users/octocat"
138
+ },
139
+ "files" => {
140
+ "ring.erl" => {
141
+ "size" => 932,
142
+ "filename" => "ring.erl",
143
+ "raw_url" => "https://gist.github.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl"
144
+ }
145
+ },
146
+ "comments" => 0,
147
+ "comments_url" => "https://api.github.com/gists/6fb6af8cb6e26dbbc327/comments/",
148
+ "html_url" => "https://gist.github.com/1",
149
+ "git_pull_url" => "git://gist.github.com/1.git",
150
+ "git_push_url" => "git@gist.github.com:1.git",
151
+ "created_at" => "2010-04-14T02:15:15Z"
152
+ }
153
+ ].to_json.should be_json_as([
154
+ {
155
+ "url" => /^https:/,
156
+ "id" => /^\d+$/,
157
+ "description" => /gist/,
158
+ "public" => true,
159
+ "user" => Hash,
160
+ "files" => Hash,
161
+ "comments" => Fixnum,
162
+ "comments_url" => /^https:/,
163
+ "html_url" => /^https:/,
164
+ "git_pull_url" => /^git:/,
165
+ "git_push_url" => /^git@/,
166
+ "created_at" => /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/,
167
+ }
168
+ ])
169
+ end
28
170
  end
29
171
  end
30
172
 
31
- context "with valid JSON" do
32
- it "matches with handy patterns" do
33
- [
173
+ describe "#be_json_including" do
174
+ context "with invalid JSON" do
175
+ it "does not match" do
176
+ "".should_not be_json_including("a" => "b")
177
+ end
178
+ end
179
+
180
+ context "with few keys" do
181
+ it "matches" do
34
182
  {
35
- "url" => "https://api.github.com/gists/17a07d0a27fd3f708f5f",
36
- "id" => "1",
37
- "description" => "description of gist",
38
- "public" => true,
39
- "user" => {
40
- "login" => "octocat",
41
- "id" => 1,
42
- "avatar_url" => "https://github.com/images/error/octocat_happy.gif",
43
- "gravatar_id" => "somehexcode",
44
- "url" => "https://api.github.com/users/octocat"
45
- },
46
- "files" => {
47
- "ring.erl" => {
48
- "size" => 932,
49
- "filename" => "ring.erl",
50
- "raw_url" => "https://gist.github.com/raw/365370/8c4d2d43d178df44f4c03a7f2ac0ff512853564e/ring.erl"
51
- }
52
- },
53
- "comments" => 0,
54
- "comments_url" => "https://api.github.com/gists/6fb6af8cb6e26dbbc327/comments/",
55
- "html_url" => "https://gist.github.com/1",
56
- "git_pull_url" => "git://gist.github.com/1.git",
57
- "git_push_url" => "git@gist.github.com:1.git",
58
- "created_at" => "2010-04-14T02:15:15Z"
59
- }
60
- ].to_json.should be_json([
183
+ "a" => 1,
184
+ "b" => 2,
185
+ }.to_json.should be_json_including(
186
+ "a" => 1,
187
+ )
188
+ end
189
+ end
190
+
191
+ context "with too many keys" do
192
+ it "matches" do
61
193
  {
62
- "url" => /^https:/,
63
- "id" => /^\d+$/,
64
- "description" => /gist/,
65
- "public" => true,
66
- "user" => Hash,
67
- "files" => Hash,
68
- "comments" => Fixnum,
69
- "comments_url" => /^https:/,
70
- "html_url" => /^https:/,
71
- "git_pull_url" => /^git:/,
72
- "git_push_url" => /^git@/,
73
- "created_at" => /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/,
74
- }
75
- ])
194
+ "a" => 1,
195
+ }.to_json.should_not be_json_including(
196
+ "a" => 1,
197
+ "b" => 2,
198
+ )
199
+ end
200
+ end
201
+
202
+ context "with different values" do
203
+ it "does not match" do
204
+ {
205
+ "a" => 1,
206
+ "b" => 2,
207
+ }.to_json.should_not be_json_including(
208
+ "a" => 2,
209
+ "b" => 2,
210
+ )
211
+ end
212
+ end
213
+
214
+ context "with same keys and values" do
215
+ it "matches" do
216
+ {
217
+ "a" => 1,
218
+ "b" => 2,
219
+ }.to_json.should be_json_including(
220
+ "a" => 1,
221
+ "b" => 2,
222
+ )
223
+ end
224
+ end
225
+
226
+ context "with nil values" do
227
+ it "does not match" do
228
+ {
229
+ "a" => nil,
230
+ }.to_json.should_not be_json_including(
231
+ "b" => nil,
232
+ )
233
+ end
234
+ end
235
+
236
+ context "with subset array" do
237
+ it "does not match" do
238
+ [
239
+ "a",
240
+ "b",
241
+ ].to_json.should be_json_including(
242
+ [
243
+ "a",
244
+ ],
245
+ )
246
+ end
247
+ end
248
+
249
+ context "with superset array" do
250
+ it "does not match" do
251
+ [
252
+ "a",
253
+ "b",
254
+ ].to_json.should_not be_json_including(
255
+ [
256
+ "a",
257
+ "b",
258
+ "c",
259
+ ],
260
+ )
261
+ end
262
+ end
263
+
264
+ context "with superset array with nil" do
265
+ it "does not match" do
266
+ [
267
+ "a",
268
+ "b",
269
+ ].to_json.should_not be_json_including(
270
+ [
271
+ "a",
272
+ "b",
273
+ nil,
274
+ ],
275
+ )
276
+ end
76
277
  end
77
278
  end
78
279
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-json_matcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryo Nakamura
@@ -95,6 +95,12 @@ files:
95
95
  - Rakefile
96
96
  - lib/rspec-json_matcher.rb
97
97
  - lib/rspec/json_matcher.rb
98
+ - lib/rspec/json_matcher/abstract_comparer.rb
99
+ - lib/rspec/json_matcher/abstract_matcher.rb
100
+ - lib/rspec/json_matcher/exact_comparer.rb
101
+ - lib/rspec/json_matcher/exact_matcher.rb
102
+ - lib/rspec/json_matcher/fuzzy_comparer.rb
103
+ - lib/rspec/json_matcher/fuzzy_matcher.rb
98
104
  - lib/rspec/json_matcher/version.rb
99
105
  - rspec-json_matcher.gemspec
100
106
  - spec/rspec/json_matcher_spec.rb