spaceborne 0.1.34 → 0.1.38

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: ed2b70eae7ff4cd66202c0ef963bf539cdac37d658f129477a6af64b4d67b539
4
- data.tar.gz: 1d2a5c1459ceb279de96815c6943d792c21fc6cef570360798899022c44e3232
3
+ metadata.gz: d742ea06ad022126a7a61fb008131b02d0f0f1db485d832570b85f845299c655
4
+ data.tar.gz: d7d452c83c164adebc69df71aef6aa2f12d50375be2e354463f7b7789b07c290
5
5
  SHA512:
6
- metadata.gz: b3202e108670a8f93f764c17fe2016ba6f424de12deb4f558cc130cfd0c0da77bfc0772f8f5a1b1f851fab6a557795fb95c45dc06d135b4b1ba2c52e6204c628
7
- data.tar.gz: 283767a387e194d8b73ba03a031a576be66da89adc0ee4e69d6d625566d5121b34531fb50cfc254a55af4760d60eb90c9052a9c3fb08f95561e48b9d65f9827a
6
+ metadata.gz: 7e16b9d1bc60eabc5257afb91510d4a715bd8ce76acccc820a255a96ad4b19f87732360d98e3dfbfcfd0f53bd2d7524a72868602df29b2bc5fa871a15128e40e
7
+ data.tar.gz: 0bac75438755e532b9d39c10864d91430d9a7d281f7d89b9ee1d1943ab7951381432fb0e48ccd39bbc95725dafb8db93a99ba4edc9a53eebec3d6c4bc8e15e59
data/README.md CHANGED
@@ -206,26 +206,35 @@ Validation for headers follows the same pattern as above, although nesting of mu
206
206
  5. It is possible to use non-json data in a request
207
207
  6. Expectations on a response with an array of hashes with keys that are unknown, but that have a defined structure are supported (using the '*' in a path)
208
208
  7. Responses that have header with Content-Encoding of gzip are gunzip'd in json_body
209
+ 8. For type checks specified in a path containing array(s), you can make the path optional, so that if the data is present it is type checked, but an empty array or element without the array is fine
209
210
 
210
- The following example shows how extension # 6 works
211
+ The following example shows how extensions # 6 & 8 work
211
212
 
212
213
  ```ruby
213
214
  { "array_of_hashes": [
214
- { "husband": {"first": "fred", "last": "flinstone"}},
215
- { "buddy": {"first": "barney", "last": "rubble"}},
216
- { "wife": {"first": "wilma", "last": "flinstone"}}
215
+ { "husband": {"first": "fred", "last": "flinstone"}},
216
+ { "buddy": {"first": "barney", "last": "rubble"}},
217
+ { "wife": {"first": "wilma", "last": "flinstone"}}
217
218
  ],
218
219
  "hash_of_hashes":
219
- { "husband": {"first": "fred", "last": "flinstone"},
220
- "buddy": {"first": "barney", "last": "rubble"},
221
- "wife": {"first": "wilma", "last": "flinstone"}
222
- }
220
+ { "husband": {"first": "fred", "last": "flinstone"},
221
+ "buddy": {"first": "barney", "last": "rubble"},
222
+ "wife": {"first": "wilma", "last": "flinstone"}
223
+ },
224
+ "lowest_array": [{ "array": [{ "present": "name" }]},
225
+ { "array": null },
226
+ { "array": [] },
227
+ { "foo": "bar" }],
228
+ "highest_array": [ null,
229
+ { "array": [{ "present": "name" }]}]
223
230
  }
224
231
  ```
225
232
  You can now validate the fact that each element in the collection has a key which is variant, but a value that has a defined format (the first and last field values are strings).
226
233
 
227
234
  expect_json_types('array_of_hashes.*.*', first: :string, last: :string)
228
235
  expect_json_types('hash_of_hashes.*', first: :string, last: :string)
236
+ expect_json_types(optional('lowest_array.*.array.*'), present: :string)
237
+ expect_json_types(optional('highest_array.*.array.*'), present: :string)
229
238
 
230
239
 
231
240
  ## Development
data/lib/spaceborne.rb CHANGED
@@ -51,8 +51,7 @@ module Spaceborne
51
51
  rescue Exception => e
52
52
  raise e unless response
53
53
 
54
- e.message << request_info
55
- raise e
54
+ raise RSpec::Expectations::ExpectationNotMetError, e.message + request_info
56
55
  end
57
56
  end
58
57
 
@@ -157,6 +156,22 @@ module Airborne
157
156
 
158
157
  # Extend airborne's expectations
159
158
  module RequestExpectations
159
+ class OptionalPathExpectations
160
+ def initialize(string)
161
+ @string = string
162
+ end
163
+ def to_s
164
+ @string.to_s
165
+ end
166
+ end
167
+
168
+ def do_process_json(part, json)
169
+ json = process_json(part, json)
170
+ rescue StandardError
171
+ raise PathError,
172
+ "Expected #{json.class}\nto be an object with property #{part}"
173
+ end
174
+
160
175
  def call_with_relative_path(data, args)
161
176
  if args.length == 2
162
177
  get_by_path(args[0], data) do |json_chunk|
@@ -205,17 +220,18 @@ module Airborne
205
220
  end
206
221
  end
207
222
  end
223
+
224
+ def optional(data)
225
+ if data.is_a?(Hash)
226
+ OptionalHashTypeExpectations.new(data)
227
+ else
228
+ OptionalPathExpectations.new(data)
229
+ end
230
+ end
208
231
  end
209
232
 
210
233
  # extension to handle hash value checking
211
234
  module PathMatcher
212
- def do_process_json(part, json)
213
- json = process_json(part, json)
214
- rescue StandardError
215
- raise PathError,
216
- "Expected #{json.class}\nto be an object with property #{part}"
217
- end
218
-
219
235
  def handle_container(json, &block)
220
236
  case json.class.name
221
237
  when 'Array'
@@ -228,44 +244,71 @@ module Airborne
228
244
  end
229
245
 
230
246
  def handle_type(type, path, json, &block)
231
- if type == '*'
247
+ case type
248
+ when '*'
232
249
  handle_container(json, &block)
233
- elsif type == '?'
250
+ when '?'
234
251
  expect_one(path, json, &block)
235
252
  else
236
253
  yield json
237
254
  end
238
255
  end
239
256
 
257
+ def make_sub_path_optional(path, sub_path)
258
+ if path.is_a?(Airborne::OptionalPathExpectations)
259
+ Airborne::OptionalPathExpectations.new(sub_path)
260
+ else
261
+ sub_path
262
+ end
263
+ end
264
+
240
265
  def iterate_path(path)
241
- raise PathError, "Invalid Path, contains '..'" if /\.\./ =~ path
266
+ raise PathError, "Invalid Path, contains '..'" if /\.\./ =~ path.to_s
242
267
 
243
268
  parts = path.to_s.split('.')
244
269
  parts.each_with_index do |part, index|
245
- yield(parts, part, index)
270
+ use_part = make_sub_path_optional(path, part)
271
+ yield(parts, use_part, index)
246
272
  end
247
273
  end
248
274
 
249
- def get_by_path(path, json, type = false, &block)
275
+ def get_by_path(path, json, type: false, &block)
250
276
  iterate_path(path) do |parts, part, index|
251
- if %w[* ?].include?(part)
277
+ if %w[* ?].include?(part.to_s)
252
278
  ensure_array_or_hash(path, json)
253
279
  type = part
254
280
  walk_with_path(type, index, path, parts, json, &block) && return if index < parts.length.pred
255
281
 
256
282
  next
257
283
  end
258
- json = do_process_json(part, json)
284
+ json = do_process_json(part.to_s, json)
259
285
  end
260
286
  handle_type(type, path, json, &block)
261
287
  end
262
288
 
263
289
  def ensure_array_or_hash(path, json)
264
- return if json.class == Array || json.class == Hash
290
+ return if json.instance_of?(Array) || json.instance_of?(Hash)
265
291
 
266
292
  raise RSpec::Expectations::ExpectationNotMetError,
267
293
  "Expected #{path} to be array or hash, got #{json.class}"\
268
294
  ' from JSON response'
269
295
  end
296
+
297
+ def walk_with_path(type, index, path, parts, json, &block)
298
+ last_error = nil
299
+ item_count = json.length
300
+ error_count = 0
301
+ json.each do |element|
302
+ begin
303
+ sub_path = parts[(index.next)...(parts.length)].join('.')
304
+ get_by_path(make_sub_path_optional(path, sub_path), element, &block)
305
+ rescue Exception => e
306
+ last_error = e
307
+ error_count += 1
308
+ end
309
+ ensure_match_all(last_error) if type == '*'
310
+ ensure_match_one(path, item_count, error_count) if type == '?'
311
+ end
312
+ end
270
313
  end
271
314
  end
@@ -1,3 +1,3 @@
1
1
  module Spaceborne
2
- VERSION = '0.1.34'.freeze
2
+ VERSION = '0.1.38'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spaceborne
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.34
4
+ version: 0.1.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith Williams
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-09 00:00:00.000000000 Z
11
+ date: 2021-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -200,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
200
200
  - !ruby/object:Gem::Version
201
201
  version: '0'
202
202
  requirements: []
203
- rubygems_version: 3.0.8
203
+ rubygems_version: 3.0.9
204
204
  signing_key:
205
205
  specification_version: 4
206
206
  summary: Gem supporting API testing