spaceborne 0.1.36 → 0.1.40

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: 8aff74d5d3bedfe5854840e95db163e1c1cd71849172d21f01067ec952b29451
4
- data.tar.gz: 6bbc1007251b0c9415d74dd838c5ea9182a9d3063d778f3c15791026a10f4537
3
+ metadata.gz: c11204f7139c5e5507dfae5c022cfbacaa4f09d9311b85c3e32824497b5e0828
4
+ data.tar.gz: 785da01072d57bb89c32fc9c021c42a0b188c1f2a188843b5c86e011a1bbac69
5
5
  SHA512:
6
- metadata.gz: 57eefe3812beebd37b2a6e879ce8b518c99fff0cb434779a122dab68b911c7ba355306009421455bac34f02ee1becde5b1bb237908678cf7b6f5d527a7973e75
7
- data.tar.gz: e9bb102e8fe35b2e65046c7bd8e7b25ff60f8bcce8173bf88da60816ea14add4df1019cd62530fd31aefe147966ead18a2675d57afd48af940fb54aaa001c695
6
+ metadata.gz: '090ba089dd166f14cd0dc259fc9887982493e4e433beafd12bb0e645e6fa2deaaade5d183868463e5325ab926508dd799e42bed866cc337004a0f196f2a8b87e'
7
+ data.tar.gz: a537d9b3bc27c998931ed409481f39cea26c2efcda803d5556848dc8f8fcca8559628ef03223b02db214cc17970794c3f6f6c0469187af91933f4ccdffc7f7a1
data/.rubocop.yml CHANGED
@@ -1,3 +1,6 @@
1
+ AllCops:
2
+ SuggestExtensions: false
3
+
1
4
  Style/FrozenStringLiteralComment:
2
5
  Enabled: false
3
6
 
@@ -23,7 +26,7 @@ Metrics/ClassLength:
23
26
  Exclude:
24
27
  - 'bin/*'
25
28
 
26
- Metrics/LineLength:
29
+ Layout/LineLength:
27
30
  Exclude:
28
31
  - 'spec/airborne/**/*.rb'
29
32
 
data/README.md CHANGED
@@ -206,26 +206,36 @@ 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" }]}],
230
+ "not_an_array": null
223
231
  }
224
232
  ```
225
233
  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
234
 
227
235
  expect_json_types('array_of_hashes.*.*', first: :string, last: :string)
228
236
  expect_json_types('hash_of_hashes.*', first: :string, last: :string)
237
+ expect_json_types(optional('lowest_array.*.array.*'), present: :string)
238
+ expect_json_types(optional('highest_array.*.array.*'), present: :string)
229
239
 
230
240
 
231
241
  ## Development
@@ -1,3 +1,3 @@
1
1
  module Spaceborne
2
- VERSION = '0.1.36'.freeze
2
+ VERSION = '0.1.40'.freeze
3
3
  end
data/lib/spaceborne.rb CHANGED
@@ -51,7 +51,7 @@ module Spaceborne
51
51
  rescue Exception => e
52
52
  raise e unless response
53
53
 
54
- raise RSpec::Expectations::ExpectationNotMetError.new(e.message + request_info)
54
+ raise RSpec::Expectations::ExpectationNotMetError, e.message + request_info
55
55
  end
56
56
  end
57
57
 
@@ -156,6 +156,24 @@ module Airborne
156
156
 
157
157
  # Extend airborne's expectations
158
158
  module RequestExpectations
159
+ # class used for holding an optional path
160
+ class OptionalPathExpectations
161
+ def initialize(string)
162
+ @string = string
163
+ end
164
+
165
+ def to_s
166
+ @string.to_s
167
+ end
168
+ end
169
+
170
+ def do_process_json(part, json)
171
+ json = process_json(part, json)
172
+ rescue StandardError
173
+ raise PathError,
174
+ "Expected #{json.class}\nto be an object with property #{part}"
175
+ end
176
+
159
177
  def call_with_relative_path(data, args)
160
178
  if args.length == 2
161
179
  get_by_path(args[0], data) do |json_chunk|
@@ -204,17 +222,18 @@ module Airborne
204
222
  end
205
223
  end
206
224
  end
225
+
226
+ def optional(data)
227
+ if data.is_a?(Hash)
228
+ OptionalHashTypeExpectations.new(data)
229
+ else
230
+ OptionalPathExpectations.new(data)
231
+ end
232
+ end
207
233
  end
208
234
 
209
235
  # extension to handle hash value checking
210
236
  module PathMatcher
211
- def do_process_json(part, json)
212
- json = process_json(part, json)
213
- rescue StandardError
214
- raise PathError,
215
- "Expected #{json.class}\nto be an object with property #{part}"
216
- end
217
-
218
237
  def handle_container(json, &block)
219
238
  case json.class.name
220
239
  when 'Array'
@@ -227,44 +246,76 @@ module Airborne
227
246
  end
228
247
 
229
248
  def handle_type(type, path, json, &block)
230
- if type == '*'
249
+ case type.to_s
250
+ when '*'
231
251
  handle_container(json, &block)
232
- elsif type == '?'
252
+ when '?'
233
253
  expect_one(path, json, &block)
234
254
  else
235
255
  yield json
236
256
  end
237
257
  end
238
258
 
259
+ def make_sub_path_optional(path, sub_path)
260
+ if path.is_a?(Airborne::OptionalPathExpectations)
261
+ Airborne::OptionalPathExpectations.new(sub_path)
262
+ else
263
+ sub_path
264
+ end
265
+ end
266
+
239
267
  def iterate_path(path)
240
- raise PathError, "Invalid Path, contains '..'" if /\.\./ =~ path
268
+ raise PathError, "Invalid Path, contains '..'" if /\.\./ =~ path.to_s
241
269
 
242
270
  parts = path.to_s.split('.')
243
271
  parts.each_with_index do |part, index|
244
- yield(parts, part, index)
272
+ use_part = make_sub_path_optional(path, part)
273
+ yield(parts, use_part, index)
245
274
  end
246
275
  end
247
276
 
248
- def get_by_path(path, json, type = false, &block)
277
+ def shortcut_validation(path, json)
278
+ json.nil? && path.is_a?(Airborne::OptionalPathExpectations)
279
+ end
280
+
281
+ def get_by_path(path, json, type: false, &block)
249
282
  iterate_path(path) do |parts, part, index|
250
- if %w[* ?].include?(part)
251
- ensure_array_or_hash(path, json)
283
+ return if shortcut_validation(path, json)
284
+
285
+ if %w[* ?].include?(part.to_s)
252
286
  type = part
253
- walk_with_path(type, index, path, parts, json, &block) && return if index < parts.length.pred
287
+ walk_with_path(type.to_s, index, path, parts, json, &block) && return if index < parts.length.pred
254
288
 
255
289
  next
256
290
  end
257
- json = do_process_json(part, json)
291
+ json = do_process_json(part.to_s, json)
258
292
  end
259
293
  handle_type(type, path, json, &block)
260
294
  end
261
295
 
262
296
  def ensure_array_or_hash(path, json)
263
- return if json.class == Array || json.class == Hash
297
+ return if json.instance_of?(Array) || json.instance_of?(Hash)
264
298
 
265
299
  raise RSpec::Expectations::ExpectationNotMetError,
266
300
  "Expected #{path} to be array or hash, got #{json.class}"\
267
301
  ' from JSON response'
268
302
  end
303
+
304
+ def walk_with_path(type, index, path, parts, json, &block)
305
+ last_error = nil
306
+ item_count = json.length
307
+ error_count = 0
308
+ json.each do |element|
309
+ begin
310
+ sub_path = parts[(index.next)...(parts.length)].join('.')
311
+ get_by_path(make_sub_path_optional(path, sub_path), element, &block)
312
+ rescue Exception => e
313
+ last_error = e
314
+ error_count += 1
315
+ end
316
+ ensure_match_all(last_error) if type == '*'
317
+ ensure_match_one(path, item_count, error_count) if type == '?'
318
+ end
319
+ end
269
320
  end
270
321
  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.36
4
+ version: 0.1.40
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-12 00:00:00.000000000 Z
11
+ date: 2021-08-23 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