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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +20 -0
- data/Appraisals +16 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +497 -0
- data/Rakefile +14 -0
- data/gemfiles/rspec_3_0.gemfile +7 -0
- data/gemfiles/rspec_3_1.gemfile +7 -0
- data/gemfiles/rspec_3_2.gemfile +7 -0
- data/gemfiles/rspec_3_3.gemfile +7 -0
- data/lib/rspec/json_matchers/comparers/abstract_comparer.rb +289 -0
- data/lib/rspec/json_matchers/comparers/comparison_result.rb +22 -0
- data/lib/rspec/json_matchers/comparers/exact_keys_comparer.rb +27 -0
- data/lib/rspec/json_matchers/comparers/include_keys_comparer.rb +27 -0
- data/lib/rspec/json_matchers/comparers.rb +13 -0
- data/lib/rspec/json_matchers/expectation.rb +78 -0
- data/lib/rspec/json_matchers/expectations/abstract.rb +36 -0
- data/lib/rspec/json_matchers/expectations/core.rb +103 -0
- data/lib/rspec/json_matchers/expectations/mixins/built_in.rb +177 -0
- data/lib/rspec/json_matchers/expectations/private.rb +181 -0
- data/lib/rspec/json_matchers/expectations.rb +14 -0
- data/lib/rspec/json_matchers/matchers/be_json_matcher.rb +92 -0
- data/lib/rspec/json_matchers/matchers/be_json_with_content_matcher.rb +21 -0
- data/lib/rspec/json_matchers/matchers/be_json_with_sizes_matcher.rb +21 -0
- data/lib/rspec/json_matchers/matchers/be_json_with_something_matcher.rb +174 -0
- data/lib/rspec/json_matchers/matchers.rb +12 -0
- data/lib/rspec/json_matchers/utils/collection_keys_extractor.rb +35 -0
- data/lib/rspec/json_matchers/utils/key_path/extraction_result.rb +22 -0
- data/lib/rspec/json_matchers/utils/key_path/extractor.rb +70 -0
- data/lib/rspec/json_matchers/utils/key_path/path.rb +104 -0
- data/lib/rspec/json_matchers/utils.rb +10 -0
- data/lib/rspec/json_matchers/version.rb +8 -0
- data/lib/rspec/json_matchers.rb +15 -0
- data/lib/rspec-json_matchers.rb +1 -0
- data/rspec-json_matchers.gemspec +47 -0
- 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
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
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
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
|
+
[](http://badge.fury.io/rb/rspec-json_matchers)
|
6
|
+
[](http://badge.fury.io/rb/rspec-json_matchers)
|
7
|
+
|
8
|
+
[](https://travis-ci.org/PikachuEXE/rspec-json_matchers)
|
9
|
+
[](https://gemnasium.com/PikachuEXE/rspec-json_matchers)
|
10
|
+
|
11
|
+
[](https://codeclimate.com/github/PikachuEXE/rspec-json_matchers)
|
12
|
+
[](https://coveralls.io/r/PikachuEXE/rspec-json_matchers)
|
13
|
+
[](https://inch-ci.org/github/PikachuEXE/rspec-json_matchers)
|
14
|
+
|
15
|
+
[](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
|