rspec-json_matchers 0.1.0.alpha.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +20 -0
  4. data/Appraisals +16 -0
  5. data/CHANGELOG.md +7 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +497 -0
  9. data/Rakefile +14 -0
  10. data/gemfiles/rspec_3_0.gemfile +7 -0
  11. data/gemfiles/rspec_3_1.gemfile +7 -0
  12. data/gemfiles/rspec_3_2.gemfile +7 -0
  13. data/gemfiles/rspec_3_3.gemfile +7 -0
  14. data/lib/rspec/json_matchers/comparers/abstract_comparer.rb +289 -0
  15. data/lib/rspec/json_matchers/comparers/comparison_result.rb +22 -0
  16. data/lib/rspec/json_matchers/comparers/exact_keys_comparer.rb +27 -0
  17. data/lib/rspec/json_matchers/comparers/include_keys_comparer.rb +27 -0
  18. data/lib/rspec/json_matchers/comparers.rb +13 -0
  19. data/lib/rspec/json_matchers/expectation.rb +78 -0
  20. data/lib/rspec/json_matchers/expectations/abstract.rb +36 -0
  21. data/lib/rspec/json_matchers/expectations/core.rb +103 -0
  22. data/lib/rspec/json_matchers/expectations/mixins/built_in.rb +177 -0
  23. data/lib/rspec/json_matchers/expectations/private.rb +181 -0
  24. data/lib/rspec/json_matchers/expectations.rb +14 -0
  25. data/lib/rspec/json_matchers/matchers/be_json_matcher.rb +92 -0
  26. data/lib/rspec/json_matchers/matchers/be_json_with_content_matcher.rb +21 -0
  27. data/lib/rspec/json_matchers/matchers/be_json_with_sizes_matcher.rb +21 -0
  28. data/lib/rspec/json_matchers/matchers/be_json_with_something_matcher.rb +174 -0
  29. data/lib/rspec/json_matchers/matchers.rb +12 -0
  30. data/lib/rspec/json_matchers/utils/collection_keys_extractor.rb +35 -0
  31. data/lib/rspec/json_matchers/utils/key_path/extraction_result.rb +22 -0
  32. data/lib/rspec/json_matchers/utils/key_path/extractor.rb +70 -0
  33. data/lib/rspec/json_matchers/utils/key_path/path.rb +104 -0
  34. data/lib/rspec/json_matchers/utils.rb +10 -0
  35. data/lib/rspec/json_matchers/version.rb +8 -0
  36. data/lib/rspec/json_matchers.rb +15 -0
  37. data/lib/rspec-json_matchers.rb +1 -0
  38. data/rspec-json_matchers.gemspec +47 -0
  39. metadata +245 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: addd43fea47a6a22fa215a491070570ff1fa9f76
4
+ data.tar.gz: 54e450f71ec0af5594bc660f73bb9a3918356a89
5
+ SHA512:
6
+ metadata.gz: b761496f1884102fb0a0e79b93d75bbbb935c176fbf1eb83942c823678791b021ffbd376c403f56185933740cae6dc7a8820628f47cb9a25330c1d04c8370595
7
+ data.tar.gz: 88a84df10ffe3bd711b92fa801147ff49abe9f35f4d9be9b6319f1cbc2991755b2150d9211d7899262c5839e6c48d31c3723b820c46e1de1f3383ad86c370f75
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.idea/
11
+ /.rspec
12
+ gemfiles/*.gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,20 @@
1
+ # Send builds to container-based infrastructure
2
+ # http://docs.travis-ci.com/user/workers/container-based-infrastructure/
3
+ sudo: false
4
+ language: ruby
5
+ cache:
6
+ - bundler
7
+ rvm:
8
+ - 2.0
9
+ - 2.1
10
+ - 2.2
11
+ - ruby-head
12
+ gemfile:
13
+ - gemfiles/rspec_3_0.gemfile
14
+ - gemfiles/rspec_3_1.gemfile
15
+ - gemfiles/rspec_3_2.gemfile
16
+ - gemfiles/rspec_3_3.gemfile
17
+ matrix:
18
+ fast_finish: true
19
+ allow_failures:
20
+ - rvm: ruby-head
data/Appraisals ADDED
@@ -0,0 +1,16 @@
1
+
2
+ appraise "rspec_3_0" do
3
+ gem "rspec", "3.0"
4
+ end
5
+
6
+ appraise "rspec_3_1" do
7
+ gem "rspec", "3.1"
8
+ end
9
+
10
+ appraise "rspec_3_2" do
11
+ gem "rspec", "3.2"
12
+ end
13
+
14
+ appraise "rspec_3_3" do
15
+ gem "rspec", "3.3"
16
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # Change Log
2
+ All notable changes to this project will be documented in this file.
3
+ This project adheres to [Semantic Versioning](http://semver.org/).
4
+
5
+ ## Unreleased
6
+ ### Added
7
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rspec-json_matchers.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 PikachuEXE
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,497 @@
1
+ # RSpec::JsonMatchers
2
+
3
+ A collection of RSpec matchers for testing JSON data.
4
+
5
+ [![Gem Version](http://img.shields.io/gem/v/rspec-json_matchers.svg?style=flat-square)](http://badge.fury.io/rb/rspec-json_matchers)
6
+ [![License](https://img.shields.io/github/license/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](http://badge.fury.io/rb/rspec-json_matchers)
7
+
8
+ [![Build Status](http://img.shields.io/travis/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](https://travis-ci.org/PikachuEXE/rspec-json_matchers)
9
+ [![Dependency Status](http://img.shields.io/gemnasium/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](https://gemnasium.com/PikachuEXE/rspec-json_matchers)
10
+
11
+ [![Code Climate](http://img.shields.io/codeclimate/github/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](https://codeclimate.com/github/PikachuEXE/rspec-json_matchers)
12
+ [![Coverage Status](http://img.shields.io/coveralls/PikachuEXE/rspec-json_matchers.svg?style=flat-square)](https://coveralls.io/r/PikachuEXE/rspec-json_matchers)
13
+ [![Inch CI](https://inch-ci.org/github/PikachuEXE/rspec-json_matchers.svg?branch=master)](https://inch-ci.org/github/PikachuEXE/rspec-json_matchers)
14
+
15
+ [![Gitter](https://img.shields.io/badge/gitter-join%20chat-1dce73.svg?style=flat-square)](https://gitter.im/PikachuEXE/rspec-json_matchers)
16
+
17
+ This gem provides a collection of RSpec matchers for testing JSON data.
18
+ It aims to make JSON testing flexible & easier, especially for testing multiple properties.
19
+ It does not and will not have anything related to JSON Schema.
20
+
21
+ ## Installation
22
+
23
+ Add this line to your application's Gemfile:
24
+
25
+ ```ruby
26
+ # `require` can be set to `true` safely without too much side effect
27
+ # (except having additional modules & classes defined which could be wasting memory).
28
+ # But there is no point requiring it unless in test
29
+ # Also maybe add it inside a "group"
30
+ gem 'rspec-json_matchers', require: false
31
+ ```
32
+
33
+ And then execute:
34
+
35
+ ```bash
36
+ $ bundle
37
+ ```
38
+
39
+ Or install it yourself as:
40
+
41
+ ```bash
42
+ $ gem install rspec-json_matchers
43
+ ```
44
+
45
+ ## Usage
46
+
47
+ To include the new matchers in your examples,
48
+ add the following code somewhere which will be loaded by `rails_helper`/`spec_helper`:
49
+ ```ruby
50
+ # Remember the `required: false` suggested earlier?
51
+ # Now is the time that it is actually "required"
52
+ require "rspec-json_matchers"
53
+
54
+ # This will include matcher methods globally for all spec
55
+ # You can choose to include it conditionally, but you should decide yourself
56
+ # Or just ignore this comment if you are just trying this out
57
+ RSpec.configure do |config|
58
+ config.include RSpec::JsonMatchers::Matchers
59
+ end
60
+ ```
61
+
62
+ ### Matcher `be_json`
63
+
64
+ This is the starting point of all new matchers.
65
+ It can be used alone to ensure that the input can be parsed by `JSON` without error.
66
+
67
+ ```ruby
68
+ specify { expect("{}").to be_json } # => pass
69
+ specify { expect("[]").to be_json } # => pass
70
+ specify { expect("").to be_json } # => fail
71
+ ```
72
+
73
+ ### Matcher `be_json.with_content`
74
+
75
+ This is perhaps the most flexible & powerful matcher in this gem.
76
+
77
+
78
+ #### Content equivalence matching
79
+
80
+ When passing in "simple data values" (that represents one of JSON data types),
81
+ it matches when they have equivalent values (using `==`).
82
+ ```ruby
83
+ specify { expect("{}").to be_json.with_content(Hash.new) } # => pass
84
+ specify { expect("[]").to be_json.with_content(Array.new) } # => pass
85
+
86
+ specify { expect("{}").to be_json.with_content(Hash.new) } # => fail
87
+ specify { expect("[]").to be_json.with_content(Array.new) } # => fail
88
+
89
+ # The following line would fail when trying parse the input as JSON
90
+ # So you can be sure the input is a valid JSON
91
+ specify { expect("").to be_json.with_content(Hash.new) } # => fail
92
+ ```
93
+
94
+ Since it's common to have multiple "properties" in an object,
95
+ the gem allows multiple key as well, instead of having to create multiple examples for all properties you want to test.
96
+ ```ruby
97
+ # Ruby object + `to_json` + Symbol keys is used for easier typing in the following examples,
98
+ # but the actual JSON string won't change.
99
+
100
+ # Matching object with single key with String keys in expected
101
+ specify { expect({a: 1}.to_json).to be_json.with_content({"a" => 1}) } # => pass
102
+ # Matching object with single key with Symbol keys in expected
103
+ # Symbol keys will be used in the remaining examples, String keys can also be used interchangeably
104
+ specify { expect({a: 1}.to_json).to be_json.with_content({a: 1}) } # => pass
105
+
106
+ # Obviously
107
+ specify { expect({a: 1}.to_json).to be_json.with_content({a: 2}) } # => fail
108
+
109
+ # The input can have more keys than expected without failing by default
110
+ specify { expect({a: 1, b: 2}.to_json).to be_json.with_content({a: 1}) } # => pass
111
+ # The actual cannot have less keys than expected or will fail the example all the time
112
+ specify { expect({a: 1}.to_json).to be_json.with_content({a: 1, b: 2}) } # => fail
113
+ ```
114
+
115
+ It's possible to make examples fail when the object represented by JSON string in `subject`
116
+ contains more keys than that in expectation using `with_exact_keys`.
117
+
118
+ ```ruby
119
+ # The spec can be set to fail when actual has more keys than expected
120
+ specify { expect({a: 1, b: 2}.to_json).to be_json.with_content({a: 1}).with_exact_keys } # => fail
121
+ ```
122
+
123
+ A "path" can also be specified for testing deeply nested data.
124
+
125
+ ```ruby
126
+ context "when input is an Hash (in Ruby)" do
127
+ subject do
128
+ {
129
+ a: {
130
+ b: {
131
+ c: 1,
132
+ },
133
+ },
134
+ }.to_json
135
+ end
136
+
137
+ it { should be_json.with_content({a: {b: {c: 1}}}) } # => pass
138
+
139
+ it { should be_json.with_content({b: {c: 1}}).at_path("a") } # => pass
140
+ it { should be_json.with_content({c: 1}).at_path("a.b") } # => pass
141
+ it { should be_json.with_content(1).at_path("a.b.c") } # => pass
142
+
143
+ # subject without data at path will cause the example to fail
144
+ it { should be_json.with_content(1).at_path("a.b.d") } # => fail
145
+ it { should be_json.with_content(1).at_path("a.b.c.d") } # => fail
146
+
147
+ # Invalid path will cause the gem to fail, `should` or `should_not`
148
+ # To avoid false positive when used with `should_not`
149
+ it { should be_json.with_content("whatever").at_path(".") } # => fail
150
+ it { should be_json.with_content("whatever").at_path(".a.") } # => fail
151
+ it { should be_json.with_content("whatever").at_path("a..c") } # => fail
152
+
153
+ it { should_not be_json.with_content("whatever").at_path(".") } # => fail
154
+ it { should_not be_json.with_content("whatever").at_path(".a.") } # => fail
155
+ it { should_not be_json.with_content("whatever").at_path("a..c") } # => fail
156
+
157
+ # Digits can be used as well in path
158
+ specify { expect({'1' => {'2' => 1}}.to_json).to be_json.with_content({'2' => 1}).at_path("1") }
159
+ specify { expect({'1' => {'2' => 1}}.to_json).to be_json.with_content(1).at_path("1.2") }
160
+ end
161
+
162
+ context "when input is an Array (in Ruby)" do
163
+ subject do
164
+ [
165
+ [
166
+ [
167
+ [1],
168
+ ],
169
+ ],
170
+ ].to_json
171
+ end
172
+
173
+ it { should be_json.with_content([[[1]]]) } # => pass
174
+
175
+ it { should be_json.with_content([[1]]).at_path("0") } # => pass
176
+ it { should be_json.with_content([1]).at_path("0.0") } # => pass
177
+ it { should be_json.with_content(1).at_path("0.0.0") } # => pass
178
+
179
+ # subject without data at path will cause the example to fail
180
+ it { should be_json.with_content(1).at_path("0.0.1") } # => fail
181
+ it { should be_json.with_content(1).at_path("0.0.0.0") } # => fail
182
+
183
+ # Invalid path will cause the gem to fail, `should` or `should_not`
184
+ # To avoid false positive when used with `should_not`
185
+ it { should be_json.with_content("whatever").at_path(".") } # => fail
186
+ it { should be_json.with_content("whatever").at_path(".0.") } # => fail
187
+ it { should be_json.with_content("whatever").at_path("0..0") } # => fail
188
+
189
+ it { should_not be_json.with_content("whatever").at_path(".") } # => fail
190
+ it { should_not be_json.with_content("whatever").at_path(".0.") } # => fail
191
+ it { should_not be_json.with_content("whatever").at_path("0..0") } # => fail
192
+
193
+ # The following pass for `should_not`
194
+ # Since the matcher would not know the `actual` should match the path, not the reverse one
195
+ it { should be_json.with_content("whatever").at_path("a") } # => fail
196
+
197
+ it { should_not be_json.with_content("whatever").at_path("a") } # => pass
198
+ end
199
+ ```
200
+
201
+
202
+ #### Special content matching
203
+
204
+ Besides objects representing JSON data types, there are other objects that can be passed in as special expectation.
205
+
206
+ ```ruby
207
+ # Pass when subject is a String & matches the Regex
208
+ context "when expected is a Regexp" do
209
+ specify { expect({url: "https://domain.com"}.to_json).to be_json.with_content(url: %r|^https://|) } # => pass
210
+ specify { expect({url: "http://domain.com"}.to_json).to be_json.with_content(url: %r|^https://|) } # => fail
211
+ specify { expect({url: 1}.to_json).to be_json.with_content(url: %r|^https://|) } # => fail
212
+ end
213
+
214
+ # Pass when subject is "covered" by the Range
215
+ context "when expected is a Range" do
216
+ specify { expect({age: 1}.to_json).to be_json.with_content(age: (1...10)) } # => pass
217
+ specify { expect({age: 10}.to_json).to be_json.with_content(age: (1...10)) } # => fail
218
+ specify { expect({age: '1'}.to_json).to be_json.with_content(age: (1...10)) } # => fail
219
+
220
+ # Supports whatever Range supports, using #cover?
221
+ specify { expect({age: '1'}.to_json).to be_json.with_content(age: ('1'...'10')) } # => fail
222
+ end
223
+
224
+ # Pass when callable returns true
225
+ context "when expected is a callable" do
226
+ class ExampleCallable
227
+ def self.call(v)
228
+ new.call(v)
229
+ end
230
+
231
+ def call(v)
232
+ true
233
+ end
234
+ end
235
+
236
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: proc { true }) } # => pass
237
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: lambda {|_| true }) } # => pass
238
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: -> (_) { true }) } # => pass
239
+
240
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: ExampleCallable) } # => pass
241
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: ExampleCallable.new) } # => pass
242
+
243
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: -> { true }) } # => error
244
+ specify { expect({a: "whatever"}.to_json).to be_json.with_content(a: -> (a, b) { true }) } # => error
245
+ end
246
+
247
+ # Pass when subject's class (in Ruby form) inherits / same as expected
248
+ context "when expected is a callable" do
249
+ specify { expect({a: 1}.to_json).to be_json.with_content(a: String) } # => fail
250
+ specify { expect({a: 1}.to_json).to be_json.with_content(a: Integer) } # => pass
251
+ specify { expect({a: 1}.to_json).to be_json.with_content(a: Numeric) } # => pass
252
+ end
253
+ ```
254
+
255
+
256
+ #### Custom/Complex Expectations
257
+
258
+ Passing in a `Range` like (e.g. `('a'..'c')`) is telling the example to pass
259
+ only when the actual value equals to any of the values represented by the Range `'a' / 'b' / 'c'`.
260
+
261
+ But there is no way to specify other "OR" expectations easily (e.g. `'a' / 'c'`)
262
+ since `Array` is already used for data structure expectation.
263
+ So the gem also provides a list of classes to represent these kinds of custom expectations to be used.
264
+
265
+ ##### Setup
266
+
267
+ First, it requires some setup.
268
+ You can put the following code in any sensible place like a specific spec file or `rails_helper`.
269
+ ```ruby
270
+ module Expectations
271
+ include RSpec::JsonMatchers::Expectations::Mixins::BuiltIn
272
+ end
273
+ ```
274
+
275
+ Alternatively, you can use `let` to define a module without name,
276
+ to avoid creating top-namespaced constant
277
+ ```ruby
278
+ let(:expectations) do
279
+ Module.new do
280
+ include RSpec::JsonMatchers::Expectations::Mixins::BuiltIn
281
+ end
282
+ end
283
+ ```
284
+
285
+ If you really want to save typing `expectations::` and are not afraid of constant name conflicts,
286
+ You can add the following somewhere.
287
+ Note that you must use both `before(:each)` & `stub_const` to make this work.
288
+ Please tell us if you have other methods to achieve the same effect.
289
+ ```ruby
290
+ before(:each) do
291
+ RSpec::JsonMatchers::Expectations::Mixins::BuiltIn.constants.each do |expectation_klass_name|
292
+ stub_const(
293
+ expectation_klass_name.to_s,
294
+ RSpec::JsonMatchers::Expectations::Mixins::BuiltIn.const_get(expectation_klass_name),
295
+ )
296
+ end
297
+ end
298
+ ```
299
+
300
+ ##### Usage
301
+
302
+ Now let's take a look at the actual expectation classes this gem provides:
303
+ ```ruby
304
+ # `Anything` is an expectation that always passes
305
+ # It has the same effect as passing `Object` in
306
+ # Since every Ruby form of JSON data type is an `Object`
307
+ # But this would be more verbose & clear
308
+ specify { expect({a: "a" }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
309
+ specify { expect({a: 1 }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
310
+ specify { expect({a: 1.1 }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
311
+ specify { expect({a: {} }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
312
+ specify { expect({a: [] }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
313
+ specify { expect({a: true }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
314
+ specify { expect({a: false}.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
315
+ specify { expect({a: nil }.to_json).to be_json.with_content(a: expectations::Anything) } # => pass
316
+
317
+
318
+ # `PositiveNumber` is an expectation that passes when subject is a `Numeric` and larger than 0
319
+ specify { expect({a: 1 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # => pass
320
+ specify { expect({a: 1.1 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # => pass
321
+ specify { expect({a: 0 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # => fail
322
+ specify { expect({a: 0.0 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # => fail
323
+ specify { expect({a: -1 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # => fail
324
+ specify { expect({a: -1.1 }.to_json).to be_json.with_content(a: expectations::PositiveNumber) } # => fail
325
+
326
+
327
+ # `NegativeNumber` is an expectation that passes when subject is a `Numeric` and less than 0
328
+ specify { expect({a: 1 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # => fail
329
+ specify { expect({a: 1.1 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # => fail
330
+ specify { expect({a: 0 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # => fail
331
+ specify { expect({a: 0.0 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # => fail
332
+ specify { expect({a: -1 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # => pass
333
+ specify { expect({a: -1.1 }.to_json).to be_json.with_content(a: expectations::NegativeNumber) } # => pass
334
+
335
+
336
+ # `BooleanValue` is an expectation that passes when subject is a `TrueClass` or `FalseClass`
337
+ specify { expect({a: "a" }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => fail
338
+ specify { expect({a: 1 }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => fail
339
+ specify { expect({a: 1.1 }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => fail
340
+ specify { expect({a: {} }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => fail
341
+ specify { expect({a: [] }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => fail
342
+ specify { expect({a: true }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => pass
343
+ specify { expect({a: false}.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => pass
344
+ specify { expect({a: nil }.to_json).to be_json.with_content(a: expectations::BooleanValue) } # => fail
345
+
346
+
347
+ # `ArrayOf` is an expectation that passes when subject is an `Array` and
348
+ # **ALL** elements satisfy the expectation passed in
349
+ specify { expect({a: "a" }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
350
+ specify { expect({a: 1 }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
351
+ specify { expect({a: 1.1 }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
352
+ specify { expect({a: {} }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
353
+ specify { expect({a: [] }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => pass
354
+ specify { expect({a: true }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
355
+ specify { expect({a: false}.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
356
+ specify { expect({a: nil }.to_json).to be_json.with_content(a: expectations::ArrayOf[expectations::Anything]) } # => fail
357
+
358
+ # As you see it allows empty array by default
359
+ # Since {Enumerable#all?} returns `true` when collection is empty
360
+ # You can make it fail using optional argument in {#allow_empty} or {#disallow_empty}
361
+ # Notice that {#disallow_empty} has no optional argument to avoid reading as double negative
362
+ specify do
363
+ expect({a: []}.to_json).to be_json.
364
+ with_content(a: expectations::ArrayOf[expectations::Anything].allow_empty)
365
+ end # => pass
366
+ specify do
367
+ expect({a: []}.to_json).to be_json.
368
+ with_content(a: expectations::ArrayOf[expectations::Anything].allow_empty(true))
369
+ end # => pass
370
+ specify do
371
+ expect({a: []}.to_json).to be_json.
372
+ with_content(a: expectations::ArrayOf[expectations::Anything].allow_empty(false))
373
+ end # => fail
374
+ specify do
375
+ expect({a: []}.to_json).to be_json.
376
+ with_content(a: expectations::ArrayOf[expectations::Anything].disallow_empty)
377
+ end # => fail
378
+
379
+
380
+ # `ArrayWithSize` is an expectation that passes when subject is an `Array` and
381
+ # The size satisfies the `Fixnum`, `Bignum` or `Range` passed in
382
+ # Passing "expectation" with unexpected type would simply fail the example
383
+ # This also means using `should_not` with unexpected type of "expectation" always pass
384
+ specify do
385
+ expect({a: [1]}.to_json).to be_json.
386
+ with_content(a: expectations::ArrayWithSize[1])
387
+ end # => pass
388
+ specify do
389
+ expect({a: [1]}.to_json).to be_json.
390
+ with_content(a: expectations::ArrayWithSize[0..2])
391
+ end # => pass
392
+ specify do
393
+ expect({a: [1]}.to_json).to be_json.
394
+ with_content(a: expectations::ArrayWithSize[1.1])
395
+ end # => error
396
+
397
+ # You can pass more than 1 objects in as expectation
398
+ # It will pass when ANY of them "expects" the size
399
+ specify do
400
+ expect({a: [1]}.to_json).to be_json.
401
+ with_content(a: expectations::ArrayWithSize[0, 1, 3])
402
+ end # => pass
403
+
404
+
405
+ # `AnyOf` is an expectation that passes when **any** of "expectations" passed in
406
+ # "expects" the subject
407
+ # It will convert non `Expectation` objects into `Expectation` objects,
408
+ # just like using `with_content` alone
409
+ specify do
410
+ expect({a: 1}.to_json).to be_json.
411
+ with_content(a: expectations::AnyOf[1])
412
+ end # => pass
413
+ specify do
414
+ expect({a: 1}.to_json).to be_json.
415
+ with_content(a: expectations::AnyOf[0, 1, 2])
416
+ end # => pass
417
+ specify do
418
+ expect({a: 1}.to_json).to be_json.
419
+ with_content(a: expectations::AnyOf[false, expectations::Anything, false])
420
+ end # => pass
421
+ specify do
422
+ expect({a: 1}.to_json).to be_json.
423
+ with_content(a: expectations::AnyOf[false, false, false])
424
+ end # => fail
425
+
426
+
427
+ # `AllOf` is an expectation that passes when **all** of "expectations" passed in
428
+ # "expects" the subject
429
+ # It will convert non `Expectation` objects into `Expectation` objects,
430
+ # just like using `with_content` alone
431
+ specify do
432
+ expect({a: 1}.to_json).to be_json.
433
+ with_content(a: expectations::AllOf[1])
434
+ end # => pass
435
+ specify do
436
+ expect({a: 1}.to_json).to be_json.
437
+ with_content(a: expectations::AllOf[1, (1..2), expectations::PositiveNumber])
438
+ end # => pass
439
+ specify do
440
+ expect({a: 1}.to_json).to be_json.
441
+ with_content(a: expectations::AllOf[0, 1, 2])
442
+ end # => fail
443
+ specify do
444
+ expect({a: 1}.to_json).to be_json.
445
+ with_content(a: expectations::AllOf[false, expectations::Anything, false])
446
+ end # => fail
447
+ specify do
448
+ expect({a: 1}.to_json).to be_json.
449
+ with_content(a: expectations::AllOf[false, false, false])
450
+ end # => fail
451
+ ```
452
+
453
+
454
+ ### Matcher `be_json.with_sizes`
455
+
456
+ This is a more convenient version of using `be_json.with_sizes` only with `ArrayWithSize`.
457
+ Since you can just pass `Fixnum`, `Bignum` or `Range` without typing `ArrayWithSize`.
458
+ Things like `with_exact_keys` & `at_path` can still be used.
459
+
460
+ ```ruby
461
+ specify do
462
+ expect({a: [1]}.to_json).to be_json.
463
+ with_sizes(a: 1)
464
+ end # => pass
465
+ specify do
466
+ expect({a: [1]}.to_json).to be_json.
467
+ with_sizes(a: (0..2))
468
+ end # => pass
469
+ specify do
470
+ expect({a: [1]}.to_json).to be_json.
471
+ with_sizes(a: 1.1)
472
+ end # => error
473
+
474
+ # But you can no longer pass multiple "expectations" for `AnyOf` behaviour
475
+ specify do
476
+ expect({a: [1]}.to_json).to be_json.
477
+ with_content(a: [0, 1, 3])
478
+ end # => fail, expects {a: [[], [1], [1, 2, 3]])
479
+ ```
480
+
481
+
482
+ ### Matcher `be_json.with_types`
483
+
484
+ Unlike gems such as
485
+ [`airborne`](https://github.com/brooklynDev/airborne) or
486
+ [`json_spec`](https://github.com/collectiveidea/json_spec),
487
+ there is no such matcher.
488
+ Just use `be_json.with_content` with classes.
489
+
490
+
491
+ ## Contributing
492
+
493
+ 1. Fork it ( https://github.com/PikachuEXE/rspec-json_matchers/fork )
494
+ 2. Create your branch (Preferred to be prefixed with `feature`/`fix`/other sensible prefixes)
495
+ 3. Commit your changes (No version related changes will be accepted)
496
+ 4. Push to the branch on your forked repo
497
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "appraisal"
2
+ require "rubygems"
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
9
+ task :default do
10
+ sh "appraisal install && rake appraisal spec"
11
+ end
12
+ else
13
+ task :default => :spec
14
+ end
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "3.0"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "3.1"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "3.2"
6
+
7
+ gemspec :path => "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "3.3"
6
+
7
+ gemspec :path => "../"