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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4564a821e55e9336df4d64292765c8e366e1e262
4
- data.tar.gz: 990b4033d9123af1ee0b471d6117f2f570a250e1
3
+ metadata.gz: 27963957079b8a36781b058fbfcc5a65d05bc982
4
+ data.tar.gz: a095f424265697a18c1ba7b27359a4352393d06c
5
5
  SHA512:
6
- metadata.gz: cccc98abfaf52295b9d7f959a94bfbc2ea01310f71893018e586a2137dfaf72d93cca14ffe75af29326bd1aeed3ce511c8b452c2dc0d0999bd85d02a6bc9f233
7
- data.tar.gz: 5f4c8f525be757b44e21626a846ca45484fb13eb9690a199cfb40da244726e2b00a7e83e331cee81385267baa6002d16b400f786847e277370bc177247208f26
6
+ metadata.gz: 9868e28a5802ba5102e443adfdcdd1342371157a5aa77a7a6a0adfe84a6ed56024436c5ee9a232524f4c36d15a16a2a25fb53f51fb68067dfbaae85144c7138a
7
+ data.tar.gz: 2455390ded90bb4a99f6f64cdc48a7bc29d2d4b55a3763b0e052fdb3b71555c092a3aeca3e068404763128893e39263b329182c2427c3856d779b0fc52571c03
@@ -4,6 +4,7 @@ require 'delegate'
4
4
 
5
5
  require 'jschema/json_reference'
6
6
  require 'jschema/schema_ref'
7
+ require 'jschema/schema_uri'
7
8
  require 'jschema/schema'
8
9
  require 'jschema/simple_validator'
9
10
  require 'jschema/validator'
@@ -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 || build_external_schema(uri, schema)
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, 'Invalid URI for external schema'
62
+ fail InvalidSchema, "Invalid URI for external schema: #{uri}"
26
63
  end
27
64
 
28
- sch = JSON.parse download_schema(uri)
29
- register_schema Schema.new(sch, uri, schema.parent)
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, 'Failed to download external schema'
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 = 1
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
- root_schema = root(schema)
52
- "#{root_schema.object_id}:#{uri}"
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
@@ -9,13 +9,15 @@ module JSchema
9
9
  check_schema_version schema
10
10
 
11
11
  if (json_reference = schema['$ref'])
12
- ref_uri = URI(json_reference)
13
- SchemaRef.new(ref_uri, parent)
12
+ unescaped_ref = json_reference.gsub(/~1|~0/, '~1' => '/', '~0' => '~')
13
+ SchemaRef.new(URI(unescaped_ref), parent)
14
14
  else
15
- uri = establish_uri(schema, parent, id)
16
- jschema = new(schema, uri, parent)
17
- register_definitions schema, jschema
18
- JSONReference.register_schema jschema
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|
@@ -7,7 +7,10 @@ module JSchema
7
7
  end
8
8
 
9
9
  def __getobj__
10
- @schema ||= JSONReference.dereference(@uri, @parent)
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
- private
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
- integer?(value) || value.is_a?(Float) || value.is_a?(BigDecimal)
60
+ value.is_a?(Numeric)
64
61
  end
65
62
 
66
- def unique_non_empty_array?(value)
67
- value.is_a?(Array) &&
68
- !value.empty? &&
69
- value.size == value.uniq.size
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
- unique_non_empty_array?(value) &&
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) && !!Schema.build(schema, parent, id)
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
- unique_non_empty_array?(dependency) &&
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
@@ -6,7 +6,7 @@ module JSchema
6
6
  self.keywords = ['enum']
7
7
 
8
8
  def validate_args(enum)
9
- unique_non_empty_array?(enum) || invalid_schema('enum', enum)
9
+ non_empty_array?(enum) || invalid_schema('enum', enum)
10
10
  end
11
11
 
12
12
  def post_initialize(enum)
@@ -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
- div_remainder = instance.abs % @multiple_of
22
- unless div_remainder.abs < 1e-6
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
@@ -14,7 +14,7 @@ module JSchema
14
14
  def validate_args(pattern)
15
15
  Regexp.new(pattern)
16
16
  true
17
- rescue TypeError, PrimitiveFailure
17
+ rescue TypeError, PrimitiveFailure, RegexpError
18
18
  invalid_schema 'pattern', pattern
19
19
  end
20
20
 
@@ -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 = properties
41
- @additional_properties = additional_properties
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
- properties_schema(field),
72
- additional_properties_schema(field),
73
- *pattern_properties_schema(field)
74
- ].compact
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(field)
86
- if @additional_properties.is_a?(Hash)
87
- if (sch = @additional_properties[field])
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, 'patternProperties')
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
- if instance[required_property].nil?
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
- unique_non_empty_array?(required) &&
29
+ non_empty_array?(required) &&
30
30
  required.all? { |req| req.is_a?(String) }
31
31
  end
32
32
  end
@@ -6,7 +6,7 @@ module JSchema
6
6
  self.keywords = ['type']
7
7
 
8
8
  def validate_args(type)
9
- if type.is_a?(String) || unique_non_empty_array?(type)
9
+ if type.is_a?(String) || non_empty_array?(type)
10
10
  true
11
11
  else
12
12
  invalid_schema 'type', type
@@ -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), 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), schema1
22
- assert_equal dereference(schema2), 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
- OpenStruct.new(uri: URI(uri), id: generate_id)
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
@@ -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 URI(schema_def_uri), definition.uri
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
@@ -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
@@ -94,7 +94,7 @@ class TestDependencies < Minitest::Test
94
94
  validator_stub =
95
95
  Struct.new(:valid) do
96
96
  def validate(_)
97
- valid ? [] : ['error']
97
+ 'error' unless valid
98
98
  end
99
99
  end
100
100
 
@@ -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' => [generate_schema, generate_schema] }
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.2
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: 2013-12-29 00:00:00.000000000 Z
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.0
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