rspec-json_matcher 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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