spaceborne 0.1.35 → 0.1.39
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/README.md +18 -8
- data/lib/spaceborne/version.rb +1 -1
- data/lib/spaceborne.rb +71 -17
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47de2c6cb6679f19995cba98157fcf914e181ca5cfc1a7c2be9f011fd593851f
|
4
|
+
data.tar.gz: 1d598c51e65a741cfa8431c6d603aecca8efe4e6077f4a08f39461a8f1bd980b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d08b29b7f93b28aa1f0c1a54b9576483ac0e35d30c42c5c8f9ac62fe157ebea7832175e46df61997398b2f7c3f5f2cbc097b79dcee40b39a84d92e09c3e8167
|
7
|
+
data.tar.gz: ef1903aa05502a28b612046382a2b06612a6231a2582b6e9555c3f138d54b10fbee6cc2fbc5c0c1f16413f733f34d015c53f837ec1531d677de067d9b80c6e27
|
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
|
-
|
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
|
211
|
+
The following example shows how extensions # 6 & 8 work
|
211
212
|
|
212
213
|
```ruby
|
213
214
|
{ "array_of_hashes": [
|
214
|
-
|
215
|
-
|
216
|
-
|
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
|
-
|
220
|
-
|
221
|
-
|
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
|
data/lib/spaceborne/version.rb
CHANGED
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 ExpectationNotMetError
|
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,79 @@ module Airborne
|
|
227
246
|
end
|
228
247
|
|
229
248
|
def handle_type(type, path, json, &block)
|
230
|
-
|
249
|
+
case type
|
250
|
+
when '*'
|
231
251
|
handle_container(json, &block)
|
232
|
-
|
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
|
-
|
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
|
277
|
+
def shortcut_validation(path, json)
|
278
|
+
return true if json.nil? && path.is_a?(Airborne::OptionalPathExpectations)
|
279
|
+
|
280
|
+
ensure_array_or_hash(path, json)
|
281
|
+
false
|
282
|
+
end
|
283
|
+
|
284
|
+
def get_by_path(path, json, type: false, &block)
|
249
285
|
iterate_path(path) do |parts, part, index|
|
250
|
-
if %w[* ?].include?(part)
|
251
|
-
|
286
|
+
if %w[* ?].include?(part.to_s)
|
287
|
+
return if shortcut_validation(path, json)
|
288
|
+
|
252
289
|
type = part
|
253
290
|
walk_with_path(type, index, path, parts, json, &block) && return if index < parts.length.pred
|
254
291
|
|
255
292
|
next
|
256
293
|
end
|
257
|
-
json = do_process_json(part, json)
|
294
|
+
json = do_process_json(part.to_s, json)
|
258
295
|
end
|
259
296
|
handle_type(type, path, json, &block)
|
260
297
|
end
|
261
298
|
|
262
299
|
def ensure_array_or_hash(path, json)
|
263
|
-
return if json.
|
300
|
+
return if json.instance_of?(Array) || json.instance_of?(Hash)
|
264
301
|
|
265
302
|
raise RSpec::Expectations::ExpectationNotMetError,
|
266
303
|
"Expected #{path} to be array or hash, got #{json.class}"\
|
267
304
|
' from JSON response'
|
268
305
|
end
|
306
|
+
|
307
|
+
def walk_with_path(type, index, path, parts, json, &block)
|
308
|
+
last_error = nil
|
309
|
+
item_count = json.length
|
310
|
+
error_count = 0
|
311
|
+
json.each do |element|
|
312
|
+
begin
|
313
|
+
sub_path = parts[(index.next)...(parts.length)].join('.')
|
314
|
+
get_by_path(make_sub_path_optional(path, sub_path), element, &block)
|
315
|
+
rescue Exception => e
|
316
|
+
last_error = e
|
317
|
+
error_count += 1
|
318
|
+
end
|
319
|
+
ensure_match_all(last_error) if type == '*'
|
320
|
+
ensure_match_one(path, item_count, error_count) if type == '?'
|
321
|
+
end
|
322
|
+
end
|
269
323
|
end
|
270
324
|
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.
|
4
|
+
version: 0.1.39
|
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-
|
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.
|
203
|
+
rubygems_version: 3.0.9
|
204
204
|
signing_key:
|
205
205
|
specification_version: 4
|
206
206
|
summary: Gem supporting API testing
|