jschema 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jschema.rb +1 -0
- data/lib/jschema/json_reference.rb +55 -13
- data/lib/jschema/method_call_logger.rb +70 -0
- data/lib/jschema/schema.rb +8 -25
- data/lib/jschema/schema_ref.rb +4 -1
- data/lib/jschema/schema_uri.rb +37 -0
- data/lib/jschema/simple_validator.rb +12 -12
- data/lib/jschema/validator/dependencies.rb +3 -3
- data/lib/jschema/validator/enum.rb +1 -1
- data/lib/jschema/validator/format.rb +8 -1
- data/lib/jschema/validator/items.rb +2 -2
- data/lib/jschema/validator/multiple_of.rb +4 -3
- data/lib/jschema/validator/pattern.rb +1 -1
- data/lib/jschema/validator/properties.rb +31 -20
- data/lib/jschema/validator/required.rb +2 -2
- data/lib/jschema/validator/type.rb +1 -1
- data/test/test_json_reference.rb +40 -9
- data/test/test_schema.rb +34 -37
- data/test/test_schema_ref.rb +8 -0
- data/test/test_schema_uri.rb +56 -0
- data/test/validator/test_dependencies.rb +1 -1
- data/test/validator/test_format.rb +8 -0
- data/test/validator/test_items.rb +7 -1
- data/test/validator/test_properties.rb +0 -8
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27963957079b8a36781b058fbfcc5a65d05bc982
|
4
|
+
data.tar.gz: a095f424265697a18c1ba7b27359a4352393d06c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9868e28a5802ba5102e443adfdcdd1342371157a5aa77a7a6a0adfe84a6ed56024436c5ee9a232524f4c36d15a16a2a25fb53f51fb68067dfbaae85144c7138a
|
7
|
+
data.tar.gz: 2455390ded90bb4a99f6f64cdc48a7bc29d2d4b55a3763b0e052fdb3b71555c092a3aeca3e068404763128893e39263b329182c2427c3856d779b0fc52571c03
|
data/lib/jschema.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module JSchema
|
2
4
|
module JSONReference
|
3
5
|
@mutex = Mutex.new
|
@@ -5,30 +7,66 @@ module JSchema
|
|
5
7
|
|
6
8
|
class << self
|
7
9
|
def register_schema(schema)
|
8
|
-
schema_key = key(schema.uri, schema)
|
10
|
+
schema_key = key(normalize(schema.uri), schema)
|
11
|
+
|
9
12
|
@mutex.synchronize do
|
10
13
|
@schemas[schema_key] = schema
|
11
14
|
end
|
12
15
|
end
|
13
16
|
|
14
17
|
def dereference(uri, schema)
|
15
|
-
schema_key = key(uri, schema)
|
16
|
-
@mutex.synchronize do
|
17
|
-
@schemas[schema_key]
|
18
|
-
end
|
18
|
+
schema_key = key(expand_uri(uri, schema), schema)
|
19
|
+
cached_schema = @mutex.synchronize do
|
20
|
+
@schemas[schema_key] if schema_key
|
21
|
+
end
|
22
|
+
|
23
|
+
if cached_schema
|
24
|
+
cached_schema
|
25
|
+
elsif uri.absolute? && !schema_part?(uri, schema)
|
26
|
+
build_external_schema(uri, schema)
|
27
|
+
end
|
19
28
|
end
|
20
29
|
|
21
30
|
private
|
22
31
|
|
32
|
+
def expand_uri(uri, schema)
|
33
|
+
if schema && schema.uri.absolute?
|
34
|
+
normalize schema.uri.merge(uri)
|
35
|
+
else
|
36
|
+
normalize uri
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def normalize(uri)
|
41
|
+
normalized = uri.dup
|
42
|
+
normalized.fragment = nil if normalized.fragment == ''
|
43
|
+
normalized.normalize
|
44
|
+
end
|
45
|
+
|
46
|
+
def schema_part?(uri, schema)
|
47
|
+
if schema
|
48
|
+
uri1_base = uri.dup
|
49
|
+
uri1_base.fragment = ''
|
50
|
+
|
51
|
+
uri2_base = schema.uri.dup
|
52
|
+
uri2_base.fragment = ''
|
53
|
+
|
54
|
+
uri1_base == uri2_base
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
23
60
|
def build_external_schema(uri, schema)
|
24
61
|
unless valid_external_uri?(uri)
|
25
|
-
fail InvalidSchema,
|
62
|
+
fail InvalidSchema, "Invalid URI for external schema: #{uri}"
|
26
63
|
end
|
27
64
|
|
28
|
-
|
29
|
-
|
65
|
+
schema_data = JSON.parse download_schema(uri)
|
66
|
+
parent_schema = schema && schema.parent
|
67
|
+
Schema.build(schema_data, parent_schema, uri.to_s)
|
30
68
|
rescue JSON::ParserError, Timeout::Error
|
31
|
-
raise InvalidSchema,
|
69
|
+
raise InvalidSchema, "Failed to download external schema: #{uri}"
|
32
70
|
end
|
33
71
|
|
34
72
|
def valid_external_uri?(uri)
|
@@ -40,16 +78,20 @@ module JSchema
|
|
40
78
|
request['Accept'] = 'application/json+schema'
|
41
79
|
|
42
80
|
http = Net::HTTP.new(uri.hostname, uri.port)
|
43
|
-
http.read_timeout =
|
81
|
+
http.read_timeout = 3
|
82
|
+
http.open_timeout = 2
|
44
83
|
http.continue_timeout = 1
|
45
|
-
http.open_timeout = 1
|
46
84
|
|
47
85
|
http.request(request).body
|
48
86
|
end
|
49
87
|
|
50
88
|
def key(uri, schema)
|
51
|
-
|
52
|
-
|
89
|
+
if schema
|
90
|
+
root_schema = root(schema)
|
91
|
+
"#{root_schema.object_id}:#{uri}"
|
92
|
+
else
|
93
|
+
uri.to_s
|
94
|
+
end
|
53
95
|
end
|
54
96
|
|
55
97
|
def root(schema)
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
# Unobtrusive logger for method calls.
|
4
|
+
module JSchema
|
5
|
+
module MethodCallLogger
|
6
|
+
class << self
|
7
|
+
def enable(log_class)
|
8
|
+
sub_classes = [log_class]
|
9
|
+
sub_classes.each do |klass|
|
10
|
+
# We want to observe only the given class and all its subclasses
|
11
|
+
observe_class klass
|
12
|
+
|
13
|
+
klass.constants.each do |class_sym|
|
14
|
+
sub_class = klass.const_get(class_sym)
|
15
|
+
|
16
|
+
# FIXME: misleading condintion
|
17
|
+
if sub_class.is_a?(Module) &&
|
18
|
+
sub_class.name.start_with?(log_class.name)
|
19
|
+
|
20
|
+
sub_classes << sub_class
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def log_method_call(klass, method, args)
|
27
|
+
logger.info "#{klass.name}##{method}(#{args.join(', ')})"
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def logger
|
33
|
+
@logger ||= Logger.new(STDOUT)
|
34
|
+
end
|
35
|
+
|
36
|
+
def observe_class(observable)
|
37
|
+
# Override public instance methods
|
38
|
+
observable.public_instance_methods(false).each do |method|
|
39
|
+
observable.class_eval do
|
40
|
+
|
41
|
+
# Redefine each public method so that each method call is logged
|
42
|
+
# first and then it is forwarded to the origin method
|
43
|
+
|
44
|
+
original_method = public_instance_method(method)
|
45
|
+
|
46
|
+
define_method(method) do |*args, &block|
|
47
|
+
MethodCallLogger.log_method_call self.class, method, args
|
48
|
+
original_method.bind(self).call(*args, &block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Override public "class" methods
|
54
|
+
observable.methods(false).each do |method|
|
55
|
+
original_method = observable.method(method).unbind
|
56
|
+
observable.define_singleton_method(method) do |*args, &block|
|
57
|
+
|
58
|
+
# FIXME: The following line causes ruby (2.1.2 p95) to crash
|
59
|
+
# MethodCallLogger.log_method_call observable, method, args
|
60
|
+
# But it works when the method is inserted "inline"
|
61
|
+
logger = Logger.new(STDOUT)
|
62
|
+
logger.info "#{observable.name}.#{method}(#{args.join(', ')})"
|
63
|
+
|
64
|
+
original_method.bind(self).call(*args, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/jschema/schema.rb
CHANGED
@@ -9,13 +9,15 @@ module JSchema
|
|
9
9
|
check_schema_version schema
|
10
10
|
|
11
11
|
if (json_reference = schema['$ref'])
|
12
|
-
|
13
|
-
SchemaRef.new(
|
12
|
+
unescaped_ref = json_reference.gsub(/~1|~0/, '~1' => '/', '~0' => '~')
|
13
|
+
SchemaRef.new(URI(unescaped_ref), parent)
|
14
14
|
else
|
15
|
-
uri =
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
uri = SchemaURI.build(schema['id'], parent, id)
|
16
|
+
parent && JSONReference.dereference(uri, parent) || begin
|
17
|
+
jschema = new(schema, uri, parent)
|
18
|
+
register_definitions schema, jschema
|
19
|
+
JSONReference.register_schema jschema
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -28,25 +30,6 @@ module JSchema
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
31
|
-
# rubocop:disable MethodLength
|
32
|
-
def establish_uri(schema, parent, id)
|
33
|
-
this_id = URI(schema['id'] || id || '#')
|
34
|
-
|
35
|
-
# RFC 3986, cl. 5.1
|
36
|
-
if parent
|
37
|
-
if parent.uri.absolute?
|
38
|
-
parent.uri.merge(this_id).normalize
|
39
|
-
elsif parent.uri.path.empty?
|
40
|
-
URI('#' + File.join(parent.uri.fragment, id || '')) # FIXME
|
41
|
-
else
|
42
|
-
# RFC 3986, cl. 5.1.4
|
43
|
-
fail InvalidSchema, 'Can not establish a base URI'
|
44
|
-
end
|
45
|
-
else
|
46
|
-
this_id
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
33
|
def register_definitions(schema, parent)
|
51
34
|
if (definitions = schema['definitions'])
|
52
35
|
definitions.each do |definition, sch|
|
data/lib/jschema/schema_ref.rb
CHANGED
@@ -7,7 +7,10 @@ module JSchema
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def __getobj__
|
10
|
-
@schema ||=
|
10
|
+
@schema ||= begin
|
11
|
+
JSONReference.dereference(@uri, @parent) ||
|
12
|
+
Kernel.fail(InvalidSchema, "Failed to dereference schema: #{@uri}")
|
13
|
+
end
|
11
14
|
end
|
12
15
|
end
|
13
16
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module JSchema
|
2
|
+
class SchemaURI
|
3
|
+
class << self
|
4
|
+
# String, Schema, String
|
5
|
+
def build(schema_id, parent_schema, id)
|
6
|
+
# RFC 3986, cl. 5.1
|
7
|
+
if parent_schema
|
8
|
+
if parent_schema.uri.absolute?
|
9
|
+
new_uri_part = schema_id ||
|
10
|
+
join_fragments(parent_schema.uri.fragment, id)
|
11
|
+
|
12
|
+
parent_schema.uri.merge(new_uri_part).normalize
|
13
|
+
elsif parent_schema.uri.path.empty?
|
14
|
+
join_fragments(parent_schema.uri.fragment, id)
|
15
|
+
else
|
16
|
+
# RFC 3986, cl. 5.1.4
|
17
|
+
fail InvalidSchema, 'Cannot establish base URI'
|
18
|
+
end
|
19
|
+
else
|
20
|
+
uri(schema_id || id || '#')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def join_fragments(primary, secondary)
|
27
|
+
uri('#' + File.join(primary || '', secondary || ''))
|
28
|
+
end
|
29
|
+
|
30
|
+
def uri(uri_string)
|
31
|
+
# NOTE: We need to escape % because URI class does not allow such
|
32
|
+
# characters within URI fragment (which is wrong).
|
33
|
+
URI(URI.escape(uri_string, '%'))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -2,14 +2,11 @@ module JSchema
|
|
2
2
|
class SimpleValidator
|
3
3
|
class << self
|
4
4
|
def build(schema, parent)
|
5
|
-
# Validator keywords must be explicitly specified.
|
6
|
-
fail UnknownError unless keywords
|
7
|
-
|
8
5
|
args = schema.values_at(*keywords)
|
9
6
|
new(*args, parent) unless args.compact.empty?
|
10
7
|
end
|
11
8
|
|
12
|
-
|
9
|
+
protected
|
13
10
|
|
14
11
|
attr_accessor :keywords
|
15
12
|
end
|
@@ -60,17 +57,20 @@ module JSchema
|
|
60
57
|
end
|
61
58
|
|
62
59
|
def number?(value)
|
63
|
-
|
60
|
+
value.is_a?(Numeric)
|
64
61
|
end
|
65
62
|
|
66
|
-
def
|
67
|
-
value.is_a?(Array) &&
|
68
|
-
|
69
|
-
|
63
|
+
def non_empty_array?(value, uniqueness_check = true)
|
64
|
+
result = value.is_a?(Array) && !value.empty?
|
65
|
+
if uniqueness_check
|
66
|
+
result && value.size == value.uniq.size
|
67
|
+
else
|
68
|
+
result
|
69
|
+
end
|
70
70
|
end
|
71
71
|
|
72
|
-
def schema_array?(value, id)
|
73
|
-
|
72
|
+
def schema_array?(value, id, uniqueness_check = true)
|
73
|
+
non_empty_array?(value, uniqueness_check) &&
|
74
74
|
value.to_enum.with_index.all? do |schema, index|
|
75
75
|
full_id = [id, index].join('/')
|
76
76
|
valid_schema? schema, full_id
|
@@ -78,7 +78,7 @@ module JSchema
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def valid_schema?(schema, id)
|
81
|
-
schema.is_a?(Hash) &&
|
81
|
+
schema.is_a?(Hash) && Schema.build(schema, parent, id)
|
82
82
|
rescue InvalidSchema
|
83
83
|
false
|
84
84
|
end
|
@@ -23,7 +23,7 @@ module JSchema
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def valid_property_dependency?(dependency)
|
26
|
-
|
26
|
+
non_empty_array?(dependency) &&
|
27
27
|
dependency.all? { |property| property.is_a?(String) }
|
28
28
|
end
|
29
29
|
|
@@ -48,8 +48,8 @@ module JSchema
|
|
48
48
|
schema = Schema.build(validator, parent, property)
|
49
49
|
schema.validate(instance)
|
50
50
|
when Array
|
51
|
-
required = Validator::Required.new(validator)
|
52
|
-
required.validate(instance)
|
51
|
+
required = Validator::Required.new(validator, nil)
|
52
|
+
Array required.validate(instance)
|
53
53
|
else
|
54
54
|
fail UnknownError
|
55
55
|
end
|
@@ -9,7 +9,7 @@ module JSchema
|
|
9
9
|
|
10
10
|
def validate_args(format)
|
11
11
|
allowed_formats =
|
12
|
-
['date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uri']
|
12
|
+
['date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'regex']
|
13
13
|
|
14
14
|
if allowed_formats.include?(format)
|
15
15
|
true
|
@@ -70,6 +70,13 @@ module JSchema
|
|
70
70
|
rescue URI::InvalidURIError
|
71
71
|
false
|
72
72
|
end
|
73
|
+
|
74
|
+
def regex(instance)
|
75
|
+
Regexp.new(instance)
|
76
|
+
true
|
77
|
+
rescue TypeError, RegexpError
|
78
|
+
false
|
79
|
+
end
|
73
80
|
end
|
74
81
|
end
|
75
82
|
end
|
@@ -20,12 +20,12 @@ module JSchema
|
|
20
20
|
def items_valid?(items)
|
21
21
|
items.nil? ||
|
22
22
|
valid_schema?(items, 'items') ||
|
23
|
-
schema_array?(items, 'items') ||
|
23
|
+
schema_array?(items, 'items', false) ||
|
24
24
|
invalid_schema('items', items)
|
25
25
|
end
|
26
26
|
|
27
27
|
def post_initialize(items, additional_items)
|
28
|
-
@items = items
|
28
|
+
@items = items || {}
|
29
29
|
@additional_items = additional_items
|
30
30
|
end
|
31
31
|
|
@@ -14,12 +14,13 @@ module JSchema
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def post_initialize(multiple_of)
|
17
|
-
@multiple_of = multiple_of
|
17
|
+
@multiple_of = BigDecimal.new(multiple_of.to_s)
|
18
18
|
end
|
19
19
|
|
20
20
|
def validate_instance(instance)
|
21
|
-
|
22
|
-
|
21
|
+
number = BigDecimal.new(instance.to_s)
|
22
|
+
div_remainder = number % @multiple_of
|
23
|
+
unless div_remainder == 0
|
23
24
|
"#{instance} must be a multiple of #{@multiple_of}"
|
24
25
|
end
|
25
26
|
end
|
@@ -32,13 +32,24 @@ module JSchema
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def valid_properties?(properties)
|
35
|
-
properties.nil? ||
|
36
|
-
(properties.is_a?(Hash) && properties.all? { |_, v| v.is_a?(Hash) })
|
35
|
+
properties.nil? || properties.is_a?(Hash)
|
37
36
|
end
|
38
37
|
|
39
38
|
def post_initialize(properties, pattern_properties, additional_properties)
|
40
|
-
@properties =
|
41
|
-
|
39
|
+
@properties =
|
40
|
+
if properties.is_a?(Hash)
|
41
|
+
properties.each_with_object({}) do |(field, sch), res|
|
42
|
+
res[field] = Schema.build(sch, parent, "properties/#{field}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
@additional_properties =
|
47
|
+
if additional_properties.is_a?(Hash)
|
48
|
+
Schema.build(additional_properties, parent, 'additionalProperties')
|
49
|
+
else
|
50
|
+
additional_properties
|
51
|
+
end
|
52
|
+
|
42
53
|
@pattern_properties = pattern_properties
|
43
54
|
end
|
44
55
|
|
@@ -67,26 +78,26 @@ module JSchema
|
|
67
78
|
private
|
68
79
|
|
69
80
|
def schemas_for(field)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
81
|
+
schemas = pattern_properties_schema(field)
|
82
|
+
|
83
|
+
if (psch = properties_schema(field))
|
84
|
+
schemas << psch
|
85
|
+
end
|
86
|
+
|
87
|
+
if schemas.empty? && (asch = additional_properties_schema)
|
88
|
+
schemas << asch
|
89
|
+
end
|
90
|
+
|
91
|
+
schemas
|
75
92
|
end
|
76
93
|
|
77
94
|
def properties_schema(field)
|
78
|
-
if @properties.is_a?(Hash)
|
79
|
-
if (sch = @properties[field])
|
80
|
-
Schema.build(sch, parent, 'properties')
|
81
|
-
end
|
82
|
-
end
|
95
|
+
@properties[field] if @properties.is_a?(Hash)
|
83
96
|
end
|
84
97
|
|
85
|
-
def additional_properties_schema
|
86
|
-
if @additional_properties.
|
87
|
-
|
88
|
-
Schema.build(sch, parent, 'additionalProperties')
|
89
|
-
end
|
98
|
+
def additional_properties_schema
|
99
|
+
if @additional_properties.respond_to?(:validate)
|
100
|
+
@additional_properties
|
90
101
|
end
|
91
102
|
end
|
92
103
|
|
@@ -95,7 +106,7 @@ module JSchema
|
|
95
106
|
if @pattern_properties.is_a?(Hash)
|
96
107
|
@pattern_properties.each do |pattern, sch|
|
97
108
|
if field.match(pattern)
|
98
|
-
schemas << Schema.build(sch, parent,
|
109
|
+
schemas << Schema.build(sch, parent, "patternProperties/#{field}")
|
99
110
|
end
|
100
111
|
end
|
101
112
|
end
|
@@ -19,14 +19,14 @@ module JSchema
|
|
19
19
|
|
20
20
|
def validate_instance(instance)
|
21
21
|
@required.each do |required_property|
|
22
|
-
|
22
|
+
unless instance.key?(required_property)
|
23
23
|
return "#{instance} must have property `#{required_property}`"
|
24
24
|
end
|
25
25
|
end and nil
|
26
26
|
end
|
27
27
|
|
28
28
|
def valid_required?(required)
|
29
|
-
|
29
|
+
non_empty_array?(required) &&
|
30
30
|
required.all? { |req| req.is_a?(String) }
|
31
31
|
end
|
32
32
|
end
|
data/test/test_json_reference.rb
CHANGED
@@ -9,7 +9,7 @@ class TestJSONReference < Minitest::Test
|
|
9
9
|
def test_schema_registration_and_dereferencing
|
10
10
|
schema = generate_schema('registered')
|
11
11
|
JSchema::JSONReference.register_schema schema
|
12
|
-
assert_equal dereference(schema)
|
12
|
+
assert_equal schema, dereference(schema)
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_schema_dereferencing_with_same_uri
|
@@ -18,8 +18,8 @@ class TestJSONReference < Minitest::Test
|
|
18
18
|
JSchema::JSONReference.register_schema schema1
|
19
19
|
JSchema::JSONReference.register_schema schema2
|
20
20
|
|
21
|
-
assert_equal dereference(schema1)
|
22
|
-
assert_equal dereference(schema2)
|
21
|
+
assert_equal schema1, dereference(schema1)
|
22
|
+
assert_equal schema2, dereference(schema2)
|
23
23
|
end
|
24
24
|
|
25
25
|
def test_dereferencing_external_schema
|
@@ -29,7 +29,7 @@ class TestJSONReference < Minitest::Test
|
|
29
29
|
expected_schema_args = [external_schema, URI(schema_uri), nil]
|
30
30
|
assert_received JSchema::Schema, :new, expected_schema_args do
|
31
31
|
JSchema::JSONReference.stub :register_schema, nil do
|
32
|
-
dereference_external_schema schema_uri, external_schema.to_json
|
32
|
+
dereference_external_schema schema_uri, external_schema.to_json, false
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -62,19 +62,50 @@ class TestJSONReference < Minitest::Test
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
+
def test_dereferencing_within_schema_with_non_default_uri
|
66
|
+
schema = generate_schema('http://example.com/', false)
|
67
|
+
JSchema::JSONReference.register_schema schema
|
68
|
+
assert_equal schema, JSchema::JSONReference.dereference(URI('#'), schema)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_dereferencing_root_schema
|
72
|
+
schema1 = generate_schema('#', false)
|
73
|
+
schema2 = generate_schema('http://example.com/', false)
|
74
|
+
JSchema::JSONReference.register_schema schema1
|
75
|
+
JSchema::JSONReference.register_schema schema2
|
76
|
+
|
77
|
+
assert_equal schema2,
|
78
|
+
JSchema::JSONReference.dereference(URI('#'), schema2)
|
79
|
+
|
80
|
+
assert_equal schema2,
|
81
|
+
JSchema::JSONReference.dereference(URI('http://example.com/#'), schema2)
|
82
|
+
|
83
|
+
assert_equal schema2,
|
84
|
+
JSchema::JSONReference.dereference(URI('http://example.com/'), schema2)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_dereferencing_schema_by_slightly_different_uri
|
88
|
+
schema = generate_schema('http://example.com/#', false)
|
89
|
+
JSchema::JSONReference.register_schema schema
|
90
|
+
|
91
|
+
assert_equal schema,
|
92
|
+
JSchema::JSONReference.dereference(URI('http://example.com/'), schema)
|
93
|
+
end
|
94
|
+
|
65
95
|
private
|
66
96
|
|
67
|
-
def dereference_external_schema(uri, response_schema)
|
97
|
+
def dereference_external_schema(uri, response_schema, parent = true)
|
68
98
|
stub_request(:get, uri).to_return(body: response_schema)
|
69
|
-
dereference generate_schema(uri)
|
99
|
+
dereference generate_schema(uri, parent)
|
70
100
|
end
|
71
101
|
|
72
102
|
def dereference(schema)
|
73
|
-
JSchema::JSONReference.dereference(schema.uri, schema)
|
103
|
+
JSchema::JSONReference.dereference(schema.uri, schema.parent)
|
74
104
|
end
|
75
105
|
|
76
|
-
def generate_schema(uri)
|
77
|
-
|
106
|
+
def generate_schema(uri, parent = true)
|
107
|
+
parent_schema = generate_schema('#', false) if parent
|
108
|
+
OpenStruct.new(uri: URI(uri), id: generate_id, parent: parent_schema)
|
78
109
|
end
|
79
110
|
|
80
111
|
def generate_id
|
data/test/test_schema.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
|
+
require 'webmock/minitest'
|
2
3
|
require 'jschema'
|
3
4
|
|
4
5
|
require_relative 'assert_received'
|
@@ -25,41 +26,6 @@ class TestSchema < Minitest::Test
|
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
|
-
def test_default_schema_uri
|
29
|
-
assert_equal URI('#'), schema_uri
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_schema_uri_when_parent_is_not_specified
|
33
|
-
assert_equal URI('test'), schema_uri('test')
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_schema_uri_when_parent_uri_is_absolute
|
37
|
-
uri = schema_uri('test', 'http://example.com/')
|
38
|
-
assert_equal URI('http://example.com/test'), uri
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_schema_uri_when_parent_uri_is_relative
|
42
|
-
assert_raises(JSchema::InvalidSchema) do
|
43
|
-
schema_uri('relative/', 'relative/')
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_schema_uri_when_both_parent_and_schema_uri_are_absolute
|
48
|
-
schema_id = 'http://example.com/'
|
49
|
-
parent_id = 'http://localhost/'
|
50
|
-
uri = schema_uri(schema_id, parent_id)
|
51
|
-
assert_equal URI(schema_id), uri
|
52
|
-
end
|
53
|
-
|
54
|
-
def test_schema_uri_when_ids_are_not_specified
|
55
|
-
assert_equal URI('#/child'), schema_uri(nil, nil, 'child')
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_that_schema_uri_is_normalized
|
59
|
-
uri = schema_uri('etc/../path', 'http://Example.com')
|
60
|
-
assert_equal 'http://example.com/path', uri.to_s
|
61
|
-
end
|
62
|
-
|
63
29
|
def test_json_refenrece
|
64
30
|
schema = Object.new
|
65
31
|
JSchema::SchemaRef.stub :new, schema do
|
@@ -68,6 +34,20 @@ class TestSchema < Minitest::Test
|
|
68
34
|
end
|
69
35
|
end
|
70
36
|
|
37
|
+
def test_that_tilda_is_unescaped
|
38
|
+
expected_ref_uri = URI('#/definitions/sch~')
|
39
|
+
assert_received JSchema::SchemaRef, :new, [expected_ref_uri, nil] do
|
40
|
+
JSchema::Schema.build('$ref' => '#/definitions/sch~0')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_that_forward_slash_is_unescaped
|
45
|
+
expected_ref_uri = URI('#/definitions/sch/sch')
|
46
|
+
assert_received JSchema::SchemaRef, :new, [expected_ref_uri, nil] do
|
47
|
+
JSchema::Schema.build('$ref' => '#/definitions/sch~1sch')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
71
51
|
def test_storing_schema_in_registry
|
72
52
|
sch = Object.new
|
73
53
|
JSchema::Schema.stub :new, sch do
|
@@ -77,12 +57,29 @@ class TestSchema < Minitest::Test
|
|
77
57
|
end
|
78
58
|
end
|
79
59
|
|
60
|
+
# TODO: Make it isolated.
|
61
|
+
def test_schema_caching
|
62
|
+
parent = JSchema::Schema.build
|
63
|
+
sch = { 'type' => 'string' }
|
64
|
+
schema1 = JSchema::Schema.build(sch, parent)
|
65
|
+
schema2 = JSchema::Schema.build(sch, parent)
|
66
|
+
assert_equal schema1.object_id, schema2.object_id
|
67
|
+
end
|
68
|
+
|
69
|
+
# TODO: Make it isolated.
|
70
|
+
def test_that_root_schemas_are_not_cached
|
71
|
+
sch = { 'type' => 'string' }
|
72
|
+
schema1 = JSchema::Schema.build(sch)
|
73
|
+
schema2 = JSchema::Schema.build(sch)
|
74
|
+
refute_equal schema1.object_id, schema2.object_id
|
75
|
+
end
|
76
|
+
|
80
77
|
# TODO: Make it isolated.
|
81
78
|
def test_definitions
|
82
|
-
schema_def_uri = '#/definitions/schema1'
|
79
|
+
schema_def_uri = URI('#/definitions/schema1')
|
83
80
|
schema = JSchema::Schema.build('definitions' => { 'schema1' => {} })
|
84
81
|
definition = JSchema::SchemaRef.new(schema_def_uri, schema)
|
85
|
-
assert_equal
|
82
|
+
assert_equal schema_def_uri, definition.uri
|
86
83
|
end
|
87
84
|
|
88
85
|
def test_that_exception_is_raised_when_schema_version_is_not_supported
|
data/test/test_schema_ref.rb
CHANGED
@@ -8,4 +8,12 @@ class TestSchemaRef < Minitest::Test
|
|
8
8
|
assert_equal JSchema::SchemaRef.new(schema.uri, nil), schema
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
12
|
+
def test_that_exception_is_raised_if_reference_is_incorrect
|
13
|
+
JSchema::JSONReference.stub :dereference, nil do
|
14
|
+
assert_raises(JSchema::InvalidSchema) do
|
15
|
+
JSchema::SchemaRef.new('invalid', nil).parent
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
11
19
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'jschema'
|
3
|
+
|
4
|
+
class TestSchemaURI < Minitest::Test
|
5
|
+
def test_default_uri
|
6
|
+
assert_equal URI('#'), schema_uri
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_schema_uri_when_parent_is_not_specified
|
10
|
+
assert_equal URI('test'), schema_uri('test')
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_schema_uri_when_parent_uri_is_absolute
|
14
|
+
uri = schema_uri('test', 'http://example.com/')
|
15
|
+
assert_equal URI('http://example.com/test'), uri
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_schema_uri_when_parent_uri_is_relative
|
19
|
+
assert_raises(JSchema::InvalidSchema) do
|
20
|
+
schema_uri('relative/', 'relative/')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_schema_uri_when_both_parent_and_schema_uri_are_absolute
|
25
|
+
schema_id = 'http://example.com/'
|
26
|
+
parent_id = 'http://localhost/'
|
27
|
+
uri = schema_uri(schema_id, parent_id)
|
28
|
+
assert_equal URI(schema_id), uri
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_schema_uri_when_ids_are_not_specified
|
32
|
+
assert_equal URI('#/child'), schema_uri(nil, nil, 'child')
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_that_schema_uri_is_normalized
|
36
|
+
uri = schema_uri('etc/../path', 'http://Example.com')
|
37
|
+
assert_equal URI('http://example.com/path'), uri
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_that_implicit_schema_id_treated_as_uri_fragment
|
41
|
+
uri = schema_uri(nil, 'http://example.com/path#sch', 'sub')
|
42
|
+
assert_equal URI('http://example.com/path#sch/sub'), uri
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_escaping
|
46
|
+
uri = schema_uri(nil, '#/definitions', 'schema%')
|
47
|
+
assert_equal URI('#/definitions/schema%25'), uri
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def schema_uri(schema_id = nil, parent_id = nil, id = nil)
|
53
|
+
parent_schema = JSchema::Schema.build('id' => parent_id) if parent_id || id
|
54
|
+
JSchema::SchemaURI.build(schema_id, parent_schema, id)
|
55
|
+
end
|
56
|
+
end
|
@@ -62,6 +62,14 @@ class TestFormat < Minitest::Test
|
|
62
62
|
refute validator('uri').valid?('://')
|
63
63
|
end
|
64
64
|
|
65
|
+
def test_passing_validation_by_regex
|
66
|
+
assert validator('regex').valid?('\d+')
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_failing_validation_by_regex
|
70
|
+
refute validator('regex').valid?('**')
|
71
|
+
end
|
72
|
+
|
65
73
|
private
|
66
74
|
|
67
75
|
def validator_class
|
@@ -28,6 +28,11 @@ class TestItems < Minitest::Test
|
|
28
28
|
assert_raises_unless_schema_array 'items'
|
29
29
|
end
|
30
30
|
|
31
|
+
def test_default_value_for_items
|
32
|
+
validator = build_from_schema('additionalItems' => false)
|
33
|
+
assert validator.valid? [1, 2, 3]
|
34
|
+
end
|
35
|
+
|
31
36
|
def test_passing_validation_by_items_schema
|
32
37
|
stub_schema_validations(true) do
|
33
38
|
assert build_from_schema('items' => {}).valid?(['test'])
|
@@ -35,8 +40,9 @@ class TestItems < Minitest::Test
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def test_passing_validation_by_items_schema_array
|
43
|
+
basic_schema = generate_schema
|
38
44
|
stub_schema_validations(true) do
|
39
|
-
schema = { 'items' => [
|
45
|
+
schema = { 'items' => [basic_schema, basic_schema] }
|
40
46
|
assert build_from_schema(schema).valid?(['test', 'test'])
|
41
47
|
end
|
42
48
|
end
|
@@ -17,14 +17,6 @@ class TestProperties < Minitest::Test
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def test_invalid_properties_schema_argument
|
21
|
-
keywords.each do |keyword|
|
22
|
-
assert_raises(JSchema::InvalidSchema) do
|
23
|
-
build_from_schema(keyword => { 'test' => 1 })
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
20
|
def test_passing_properties_validation_by_sub_schema
|
29
21
|
keywords.each do |keyword|
|
30
22
|
assert_passing_validation keyword
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jschema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konstantin Papkovskiy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Implementation of JSON Schema Draft 4
|
14
14
|
email: konstantin@papkovskiy.com
|
@@ -18,8 +18,10 @@ extra_rdoc_files: []
|
|
18
18
|
files:
|
19
19
|
- lib/jschema.rb
|
20
20
|
- lib/jschema/json_reference.rb
|
21
|
+
- lib/jschema/method_call_logger.rb
|
21
22
|
- lib/jschema/schema.rb
|
22
23
|
- lib/jschema/schema_ref.rb
|
24
|
+
- lib/jschema/schema_uri.rb
|
23
25
|
- lib/jschema/simple_validator.rb
|
24
26
|
- lib/jschema/string_length_validator.rb
|
25
27
|
- lib/jschema/validator.rb
|
@@ -52,6 +54,7 @@ files:
|
|
52
54
|
- test/test_json_reference.rb
|
53
55
|
- test/test_schema.rb
|
54
56
|
- test/test_schema_ref.rb
|
57
|
+
- test/test_schema_uri.rb
|
55
58
|
- test/test_validator.rb
|
56
59
|
- test/validator/argument_is_array_of_schemas_tests.rb
|
57
60
|
- test/validator/assertions.rb
|
@@ -101,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
104
|
version: '0'
|
102
105
|
requirements: []
|
103
106
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.2.
|
107
|
+
rubygems_version: 2.2.2
|
105
108
|
signing_key:
|
106
109
|
specification_version: 4
|
107
110
|
summary: JSON Schema implementation
|
@@ -113,6 +116,7 @@ test_files:
|
|
113
116
|
- test/test_json_reference.rb
|
114
117
|
- test/test_schema.rb
|
115
118
|
- test/test_schema_ref.rb
|
119
|
+
- test/test_schema_uri.rb
|
116
120
|
- test/test_validator.rb
|
117
121
|
- test/validator/argument_is_array_of_schemas_tests.rb
|
118
122
|
- test/validator/assertions.rb
|