json_matchers 0.9.0 → 0.10.0

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 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