rspec-json_matchers 0.1.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![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
|