json_matchers 0.9.0 → 0.10.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
  SHA256:
3
- metadata.gz: 5922bc3d062651cf85a9aa16420365e544abe115adb3e79683360abf06a806e2
4
- data.tar.gz: 8413dc48cb9588a41149ebb7a710ab358138578f72f22b212a61f809bd784596
3
+ metadata.gz: 03b79f9a5c8394f6e8ccbd26d6c066519e5d2a25ad6b623765a48f524ba38bf0
4
+ data.tar.gz: 00421a6718fff3b21d1c50382ea5b9d5f855dbfe4d2522dbf50db217f2993b8f
5
5
  SHA512:
6
- metadata.gz: 88663040a28f53d62815fb2544a1c3fe7760bd294d99f373f879e7b106d269e5961da3a7a29252888d3be55da242a530cb8d2d5c533b983e4b35bf8db6a46190
7
- data.tar.gz: 1ec7eba89fcad7f02e0782032c8cdb7938d4ad1d4c575022f183881e8e75d08b8b2c76c16cd46d8eb6fda3fff481abe1cfce287802f71bbf264a1330ad8d2f45
6
+ metadata.gz: 9b4cc33ad05676e0ac2133c79d627ece2994d0a21878ad6269c3145081d3cf1fe0e193928e1ca312660baa418b69f5cd33661aa0f070301d50f51436b72d3c0a
7
+ data.tar.gz: 830aa3570c9ae06fcd3986323d2dd0a3763c7fd91c62e09cf7029e184612ec15c5227fa706afbfe3cb8471c61c4f8dd85fa2cea68f9fd5edb704f7c7bfdbfffc
@@ -4,4 +4,6 @@ language: ruby
4
4
  notifications:
5
5
  email: false
6
6
  rvm:
7
- - 2.5.0
7
+ - 2.5.0
8
+ before_install:
9
+ - gem update --system
data/NEWS.md CHANGED
@@ -1,6 +1,15 @@
1
1
  master
2
2
  ======
3
3
 
4
+ 0.10.0
5
+ ======
6
+
7
+ * *BREAKING CHANGE* Implement the validation with the `json_schema` gem instead
8
+ of `json-schema`. [#31]
9
+ * *BREAKING CHANGE* - remove support for configuring validation options.
10
+
11
+ [#31]: https://github.com/thoughtbot/json_matchers/pull/31
12
+
4
13
  0.9.0
5
14
  =====
6
15
 
data/README.md CHANGED
@@ -24,7 +24,7 @@ Or install it yourself as:
24
24
 
25
25
  Inspired by [Validating JSON Schemas with an RSpec Matcher][original-blog-post].
26
26
 
27
- [original-blog-post]: (http://robots.thoughtbot.com/validating-json-schemas-with-an-rspec-matcher)
27
+ [original-blog-post]: (https://robots.thoughtbot.com/validating-json-schemas-with-an-rspec-matcher)
28
28
 
29
29
  First, configure it in your test suite's helper file:
30
30
 
@@ -37,7 +37,7 @@ First, configure it in your test suite's helper file:
37
37
  ```ruby
38
38
  require "json_matchers/rspec"
39
39
 
40
- JsonMatchers.schema_root = "/spec/support/api/schemas"
40
+ JsonMatchers.schema_root = "spec/support/api/schemas"
41
41
  ```
42
42
 
43
43
  #### Minitest
@@ -48,33 +48,34 @@ JsonMatchers.schema_root = "/spec/support/api/schemas"
48
48
  require "minitest/autorun"
49
49
  require "json_matchers/minitest/assertions"
50
50
 
51
- JsonMatchers.schema_root = "/test/support/api/schemas"
51
+ JsonMatchers.schema_root = "test/support/api/schemas"
52
52
 
53
53
  Minitest::Test.send(:include, JsonMatchers::Minitest::Assertions)
54
54
  ```
55
55
 
56
56
  ### Declare
57
57
 
58
- Declare your [JSON Schema](http://json-schema.org/example1.html) in the schema
58
+ Declare your [JSON Schema](https://json-schema.org/example1.html) in the schema
59
59
  directory.
60
60
 
61
- `spec/support/api/schemas/posts.json` or `test/support/api/schemas/posts.json`:
61
+ `spec/support/api/schemas/location.json` or
62
+ `test/support/api/schemas/location.json`:
63
+
64
+ Define your [JSON Schema](https://json-schema.org/example1.html) in the schema
65
+ directory.
62
66
 
63
67
  ```json
64
68
  {
69
+ "id": "https://json-schema.org/geo",
70
+ "$schema": "https://json-schema.org/draft-06/schema#",
71
+ "description": "A geographical coordinate",
65
72
  "type": "object",
66
- "required": ["posts"],
67
73
  "properties": {
68
- "posts": {
69
- "type": "array",
70
- "items":{
71
- "required": ["id", "title", "body"],
72
- "properties": {
73
- "id": { "type": "integer" },
74
- "title": { "type": "string" },
75
- "body": { "type": "string" }
76
- }
77
- }
74
+ "latitude": {
75
+ "type": "number"
76
+ },
77
+ "longitude": {
78
+ "type": "number"
78
79
  }
79
80
  }
80
81
  }
@@ -87,15 +88,15 @@ directory.
87
88
  Validate a JSON response, a Hash, or a String against a JSON Schema with
88
89
  `match_json_schema`:
89
90
 
90
- `spec/requests/posts_spec.rb`
91
+ `spec/requests/locations_spec.rb`
91
92
 
92
93
  ```ruby
93
- describe "GET /posts" do
94
- it "returns Posts" do
95
- get posts_path, format: :json
94
+ describe "GET /locations" do
95
+ it "returns Locations" do
96
+ get locations_path, format: :json
96
97
 
97
98
  expect(response.status).to eq 200
98
- expect(response).to match_json_schema("posts")
99
+ expect(response).to match_json_schema("locations")
99
100
  end
100
101
  end
101
102
  ```
@@ -105,107 +106,129 @@ end
105
106
  Validate a JSON response, a Hash, or a String against a JSON Schema with
106
107
  `assert_matches_json_schema`:
107
108
 
108
- `test/integration/posts_test.rb`
109
+ `test/integration/locations_test.rb`
109
110
 
110
111
  ```ruby
111
- def test_GET_posts_returns_Posts
112
- get posts_path, format: :json
112
+ def test_GET_posts_returns_Locations
113
+ get locations_path, format: :json
113
114
 
114
115
  assert_equal response.status, 200
115
- assert_matches_json_schema response, "posts"
116
+ assert_matches_json_schema response, "locations"
116
117
  end
117
118
  ```
118
119
 
119
- ### DEPRECATED: Passing options to the validator
120
+ ### Embedding other Schemas
120
121
 
121
- The matcher accepts options, which it passes to the validator:
122
+ To re-use other schema definitions, include `$ref` keys that refer to their
123
+ definitions.
122
124
 
123
- `spec/requests/posts_spec.rb`
125
+ First, declare the singular version of your schema.
124
126
 
125
- ```ruby
126
- describe "GET /posts" do
127
- it "returns Posts" do
128
- get posts_path, format: :json
127
+ `spec/support/api/schemas/user.json`:
129
128
 
130
- expect(response.status).to eq 200
131
- expect(response).to match_json_schema("posts", strict: true)
132
- end
133
- end
129
+ ```json
130
+ {
131
+ "id": "file:/user.json#",
132
+ "type": "object",
133
+ "required": ["id"],
134
+ "properties": {
135
+ "id": { "type": "integer" },
136
+ "name": { "type": "string" },
137
+ "address": { "type": "string" },
138
+ },
139
+ }
134
140
  ```
135
141
 
136
- A list of available options can be found [here][options].
137
-
138
- [options]: https://github.com/ruby-json-schema/json-schema/blob/2.2.4/lib/json-schema/validator.rb#L160-L162
139
-
140
- ### DEPRECATED: Global matcher options
141
-
142
- To configure the default options passed to *all* matchers, call
143
- `JsonMatchers.configure`.
142
+ Then, when you declare your collection schema, reference your singular schemas.
144
143
 
145
- `spec/support/json_matchers.rb`:
144
+ `spec/support/api/schemas/users/index.json`:
146
145
 
147
- ```rb
148
- JsonMatchers.configure do |config|
149
- config.options[:strict] = true
150
- end
146
+ ```json
147
+ {
148
+ "id": "file:/users/index.json#",
149
+ "type": "object",
150
+ "definitions": {
151
+ "users": {
152
+ "description": "A collection of users",
153
+ "example": [{ "id": "1" }],
154
+ "type": "array",
155
+ "items": {
156
+ "$ref": "file:/user.json#"
157
+ },
158
+ },
159
+ },
160
+ "required": ["users"],
161
+ "properties": {
162
+ "users": {
163
+ "$ref": "#/definitions/users"
164
+ }
165
+ },
166
+ }
151
167
  ```
152
168
 
153
- A list of available options can be found [here][options].
169
+ NOTE: `$ref` resolves paths relative to the schema in question.
154
170
 
155
- ### DEPRECATED: Default matcher options
171
+ In this case `"user.json"` and `"users/index.json"` are resolved relative to
172
+ `"spec/support/api/schemas"` or `"test/support/api/schemas"`.
156
173
 
157
- * `record_errors: true` - *NOTE* `json_matchers` will always set
158
- `record_errors: true`. This cannot be overridden.
174
+ To learn more about `$ref`, check out
175
+ [Understanding JSON Schema Structuring][$ref].
159
176
 
160
- ### Embedding other Schemas
177
+ [$ref]: https://spacetelescope.github.io/understanding-json-schema/structuring.html
161
178
 
162
- To DRY up your schema definitions, use JSON schema's `$ref`.
179
+ ### Declaring a schema in a Subdirectory
163
180
 
164
- First, declare the singular version of your schema.
181
+ Nesting a schema within a subdirectory is also supported:
182
+
183
+ `spec/support/api/schemas/api/v1/location.json`:
165
184
 
166
- `spec/support/api/schemas/post.json`:
167
185
 
168
186
  ```json
169
187
  {
188
+ "id": "https://json-schema.org/geo",
189
+ "$schema": "https://json-schema.org/draft-06/schema#",
190
+ "description": "A geographical coordinate",
170
191
  "type": "object",
171
- "required": ["id", "title", "body"],
172
192
  "properties": {
173
- "id": { "type": "integer" },
174
- "title": { "type": "string" },
175
- "body": { "type": "string" }
193
+ "latitude": {
194
+ "type": "number"
195
+ },
196
+ "longitude": {
197
+ "type": "number"
198
+ }
176
199
  }
177
200
  }
178
201
  ```
179
202
 
180
- Then, when you declare your collection schema, reference your singular schemas.
203
+ `spec/requests/api/v1/locations_spec.rb`:
181
204
 
182
- `spec/support/api/schemas/posts.json`:
205
+ ```ruby
206
+ describe "GET api/v1/locations" do
207
+ it "returns Locations" do
208
+ get locations_path, format: :json
183
209
 
184
- ```json
185
- {
186
- "type": "object",
187
- "required": ["posts"],
188
- "properties": {
189
- "posts": {
190
- "type": "array",
191
- "items": { "$ref": "post.json" }
192
- }
193
- }
194
- }
210
+ expect(response.status).to eq 200
211
+ expect(response).to match_json_schema("api/v1/location")
212
+ end
213
+ end
195
214
  ```
196
215
 
197
- NOTE: `$ref` resolves paths relative to the schema in question.
216
+ ## Configuration
217
+
218
+ By default, the schema directory is `spec/support/api/schemas`.
198
219
 
199
- In this case `"post.json"` will be resolved relative to
200
- `"spec/support/api/schemas"`.
220
+ This can be configured via `JsonMatchers.schema_root`.
201
221
 
202
- To learn more about `$ref`, check out [Understanding JSON Schema Structuring](http://spacetelescope.github.io/understanding-json-schema/structuring.html)
222
+ ```ruby
223
+ # spec/support/json_matchers.rb
224
+
225
+ JsonMatchers.schema_root = "docs/api/schemas"
226
+ ```
203
227
 
204
228
  ## Upgrading from `0.9.x`
205
229
 
206
- After `json_matchers@0.9.x`, calls to `match_json_schema` and
207
- `match_response_schema` no longer accept options, and `JsonMatchers.configure`
208
- will been removed.
230
+ Calls to `match_json_schema` and `match_response_schema` no longer accept
231
+ options, and `JsonMatchers.configure` has been removed.
209
232
 
210
233
  ## Contributing
211
234
 
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency("json-schema", "~> 2.7")
21
+ spec.add_dependency("json_schema")
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.7"
24
24
  spec.add_development_dependency "pry"
@@ -1,5 +1,5 @@
1
+ require "pathname"
1
2
  require "json_matchers/version"
2
- require "json_matchers/configuration"
3
3
  require "json_matchers/matcher"
4
4
  require "json_matchers/errors"
5
5
 
@@ -9,6 +9,6 @@ module JsonMatchers
9
9
  end
10
10
 
11
11
  def self.path_to_schema(schema_name)
12
- Pathname(schema_root).join("#{schema_name}.json")
12
+ Pathname.new(schema_root).join("#{schema_name}.json")
13
13
  end
14
14
  end
@@ -5,16 +5,16 @@ require "json_matchers/matcher"
5
5
 
6
6
  module JsonMatchers
7
7
  class Assertion
8
- def initialize(schema_name, **options)
9
- @schema_name = schema_name
8
+ def initialize(schema_name)
9
+ @schema_name = schema_name.to_s
10
10
  @schema_path = JsonMatchers.path_to_schema(schema_name)
11
- @matcher = Matcher.new(schema_path, options)
11
+ @matcher = Matcher.new(schema_path)
12
12
  end
13
13
 
14
14
  def valid?(json)
15
15
  @payload = Payload.new(json)
16
16
 
17
- matcher.matches?(payload.to_s)
17
+ matcher.matches?(payload)
18
18
  end
19
19
 
20
20
  def valid_failure_message
@@ -58,7 +58,7 @@ not to match schema "#{schema_name}":
58
58
  end
59
59
 
60
60
  def schema_body
61
- File.read(schema_path)
61
+ schema_path.read
62
62
  end
63
63
 
64
64
  def format_json(json)
@@ -1,24 +1,18 @@
1
- require "json-schema"
1
+ require "json_schema"
2
+ require "json_matchers/parser"
2
3
  require "json_matchers/validator"
3
4
 
4
5
  module JsonMatchers
5
6
  class Matcher
6
- def initialize(schema_path, options = {})
7
+ def initialize(schema_path)
7
8
  @schema_path = schema_path
8
- @options = default_options.merge(options)
9
+ @document_store = build_and_populate_document_store
9
10
  end
10
11
 
11
12
  def matches?(payload)
12
- validator = build_validator(payload)
13
-
14
- self.errors = validator.validate!
13
+ self.errors = validator.validate(payload)
15
14
 
16
15
  errors.empty?
17
- rescue JSON::Schema::ValidationError => error
18
- self.errors = [error.message]
19
- false
20
- rescue JSON::Schema::JsonParseError
21
- raise InvalidSchemaError
22
16
  end
23
17
 
24
18
  def validation_failure_message
@@ -27,19 +21,22 @@ module JsonMatchers
27
21
 
28
22
  private
29
23
 
30
- attr_reader :schema_path, :options
31
24
  attr_accessor :errors
25
+ attr_reader :document_store, :schema_path
32
26
 
33
- def default_options
34
- JsonMatchers.configuration.options || {}
27
+ def validator
28
+ Validator.new(schema_path: schema_path, document_store: document_store)
35
29
  end
36
30
 
37
- def build_validator(payload)
38
- Validator.new(
39
- options: options,
40
- payload: payload,
41
- schema_path: schema_path,
42
- )
31
+ def build_and_populate_document_store
32
+ document_store = JsonSchema::DocumentStore.new
33
+
34
+ Dir.glob("#{JsonMatchers.schema_root}/**/*.json").
35
+ map { |path| Pathname.new(path) }.
36
+ map { |schema_path| Parser.new(schema_path).parse }.
37
+ each { |schema| document_store.add_schema(schema) }
38
+
39
+ document_store
43
40
  end
44
41
  end
45
42
  end
@@ -0,0 +1,21 @@
1
+ module JsonMatchers
2
+ class Parser
3
+ def initialize(schema_path)
4
+ @schema_path = schema_path
5
+ end
6
+
7
+ def parse
8
+ JsonSchema.parse!(schema_data)
9
+ rescue JSON::ParserError, JsonSchema::SchemaError => error
10
+ raise InvalidSchemaError.new(error)
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :schema_path
16
+
17
+ def schema_data
18
+ JSON.parse(schema_path.read)
19
+ end
20
+ end
21
+ end