jschema 0.0.2 → 0.1.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 +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
|