jsi 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,117 +1,131 @@
1
1
  require_relative 'test_helper'
2
2
 
3
- describe JSI::JSON::HashNode do
4
- # document of the node being tested
5
- let(:document) { {'a' => 'b', 'c' => {'d' => 'e'}} }
6
- # by default the node is the whole document
7
- let(:path) { [] }
8
- # the node being tested
9
- let(:node) { JSI::JSON::Node.new_by_type(document, path) }
3
+ document_types = [
4
+ {
5
+ make_document: -> (d) { d },
6
+ document: {'a' => 'b', 'c' => {'d' => 'e'}},
7
+ type_desc: 'Hash',
8
+ },
9
+ {
10
+ make_document: -> (d) { SortOfHash.new(d) },
11
+ document: SortOfHash.new({'a' => 'b', 'c' => SortOfHash.new({'d' => 'e'})}),
12
+ type_desc: 'sort of Hash-like',
13
+ },
14
+ ]
15
+ document_types.each do |document_type|
16
+ describe "JSI::JSON::HashNode with #{document_type[:type_desc]}" do
17
+ # document of the node being tested
18
+ let(:document) { document_type[:document] }
19
+ # by default the node is the whole document
20
+ let(:path) { [] }
21
+ # the node being tested
22
+ let(:node) { JSI::JSON::Node.new_by_type(document, path) }
10
23
 
11
- describe '#each' do
12
- it 'iterates, one argument' do
13
- out = []
14
- node.each do |arg|
15
- out << arg
24
+ describe '#each' do
25
+ it 'iterates, one argument' do
26
+ out = []
27
+ node.each do |arg|
28
+ out << arg
29
+ end
30
+ assert_instance_of(JSI::JSON::HashNode, node['c'])
31
+ assert_equal([['a', 'b'], ['c', node['c']]], out)
16
32
  end
17
- assert_instance_of(JSI::JSON::HashNode, node['c'])
18
- assert_equal([['a', 'b'], ['c', node['c']]], out)
19
- end
20
- it 'iterates, two arguments' do
21
- out = []
22
- node.each do |k, v|
23
- out << [k, v]
33
+ it 'iterates, two arguments' do
34
+ out = []
35
+ node.each do |k, v|
36
+ out << [k, v]
37
+ end
38
+ assert_instance_of(JSI::JSON::HashNode, node['c'])
39
+ assert_equal([['a', 'b'], ['c', node['c']]], out)
40
+ end
41
+ it 'returns self' do
42
+ assert_equal(node.each { }.object_id, node.object_id)
43
+ end
44
+ it 'returns an enumerator when called with no block' do
45
+ enum = node.each
46
+ assert_instance_of(Enumerator, enum)
47
+ assert_equal([['a', 'b'], ['c', node['c']]], enum.to_a)
24
48
  end
25
- assert_instance_of(JSI::JSON::HashNode, node['c'])
26
- assert_equal([['a', 'b'], ['c', node['c']]], out)
27
49
  end
28
- it 'returns self' do
29
- assert_equal(node.each { }.object_id, node.object_id)
50
+ describe '#to_hash' do
51
+ it 'returns a Hash with Nodes in' do
52
+ assert_instance_of(Hash, node.to_hash)
53
+ assert_equal({'a' => 'b', 'c' => node['c']}, node.to_hash)
54
+ end
30
55
  end
31
- it 'returns an enumerator when called with no block' do
32
- enum = node.each
33
- assert_instance_of(Enumerator, enum)
34
- assert_equal([['a', 'b'], ['c', node['c']]], enum.to_a)
56
+ describe '#merge' do
57
+ let(:document) { document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}) }
58
+ # testing the node at 'c' here, merging a hash at a path within a document.
59
+ let(:path) { ['c'] }
60
+ it 'merges' do
61
+ merged = node.merge('x' => 'y')
62
+ # check the content at 'c' was merged with the remainder of the document intact (at 'a')
63
+ assert_equal({'a' => {'b' => 0}, 'c' => {'d' => 'e', 'x' => 'y'}}, merged.document)
64
+ # check the original node retains its original document
65
+ assert_equal(document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}), node.document)
66
+ # check that unnecessary copies of unaffected parts of the document were not made
67
+ assert_equal(node.document.to_hash['a'].object_id, merged.document['a'].object_id)
68
+ end
35
69
  end
36
- end
37
- describe '#to_hash' do
38
- it 'returns a Hash with Nodes in' do
39
- assert_instance_of(Hash, node.to_hash)
40
- assert_equal({'a' => 'b', 'c' => node['c']}, node.to_hash)
70
+ describe '#as_json' do
71
+ let(:document) { document_type[:make_document].call({'a' => 'b'}) }
72
+ it '#as_json' do
73
+ assert_equal({'a' => 'b'}, node.as_json)
74
+ assert_equal({'a' => 'b'}, node.as_json(this_option: 'what?'))
75
+ end
41
76
  end
42
- end
43
- describe '#merge' do
44
- let(:document) { {'a' => {'b' => 0}, 'c' => {'d' => 'e'}} }
45
- # testing the node at 'c' here, merging a hash at a path within a document.
46
- let(:path) { ['c'] }
47
- it 'merges' do
48
- merged = node.merge('x' => 'y')
49
- # check the content at 'c' was merged with the remainder of the document intact (at 'a')
50
- assert_equal({'a' => {'b' => 0}, 'c' => {'d' => 'e', 'x' => 'y'}}, merged.document)
51
- # check the original node retains its original document
52
- assert_equal({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}, node.document)
53
- # check that unnecessary copies of unaffected parts of the document were not made
54
- assert_equal(node.document['a'].object_id, merged.document['a'].object_id)
77
+ # these methods just delegate to Hash so not going to test excessively
78
+ describe 'key only methods' do
79
+ it('#each_key') { assert_equal(['a', 'c'], node.each_key.to_a) }
80
+ it('#empty?') { assert_equal(false, node.empty?) }
81
+ it('#has_key?') { assert_equal(true, node.has_key?('a')) }
82
+ it('#include?') { assert_equal(false, node.include?('q')) }
83
+ it('#key?') { assert_equal(true, node.key?('c')) }
84
+ it('#keys') { assert_equal(['a', 'c'], node.keys) }
85
+ it('#length') { assert_equal(2, node.length) }
86
+ it('#member?') { assert_equal(false, node.member?(0)) }
87
+ it('#size') { assert_equal(2, node.size) }
55
88
  end
56
- end
57
- describe '#as_json' do
58
- let(:document) { {'a' => 'b'} }
59
- it '#as_json' do
60
- assert_equal({'a' => 'b'}, node.as_json)
61
- assert_equal({'a' => 'b'}, node.as_json(this_option: 'what?'))
62
- end
63
- end
64
- # these methods just delegate to Hash so not going to test excessively
65
- describe 'key only methods' do
66
- it('#each_key') { assert_equal(['a', 'c'], node.each_key.to_a) }
67
- it('#empty?') { assert_equal(false, node.empty?) }
68
- it('#has_key?') { assert_equal(true, node.has_key?('a')) }
69
- it('#include?') { assert_equal(false, node.include?('q')) }
70
- it('#key?') { assert_equal(true, node.key?('c')) }
71
- it('#keys') { assert_equal(['a', 'c'], node.keys) }
72
- it('#length') { assert_equal(2, node.length) }
73
- it('#member?') { assert_equal(false, node.member?(0)) }
74
- it('#size') { assert_equal(2, node.size) }
75
- end
76
- describe 'key + value methods' do
77
- it('#<') { assert_equal(true, node < {'a' => 'b', 'c' => node['c'], 'x' => 'y'}) } if {}.respond_to?(:<)
78
- it('#<=') { assert_equal(true, node <= node) } if {}.respond_to?(:<=)
79
- it('#>') { assert_equal(true, node > {}) } if {}.respond_to?(:>)
80
- it('#>=') { assert_equal(false, node >= {'foo' => 'bar'}) } if {}.respond_to?(:>=)
81
- it('#any?') { assert_equal(false, node.any? { |k, v| v == 3 }) }
82
- it('#assoc') { assert_equal(['a', 'b'], node.assoc('a')) }
83
- it('#dig') { assert_equal('e', node.dig('c', 'd')) } if {}.respond_to?(:dig)
84
- it('#each_pair') { assert_equal([['a', 'b'], ['c', node['c']]], node.each_pair.to_a) }
85
- it('#each_value') { assert_equal(['b', node['c']], node.each_value.to_a) }
86
- it('#fetch') { assert_equal('b', node.fetch('a')) }
87
- it('#fetch_values') { assert_equal(['b'], node.fetch_values('a')) } if {}.respond_to?(:fetch_values)
88
- it('#has_value?') { assert_equal(true, node.has_value?('b')) }
89
- it('#invert') { assert_equal({'b' => 'a', node['c'] => 'c'}, node.invert) }
90
- it('#key') { assert_equal('a', node.key('b')) }
91
- it('#rassoc') { assert_equal(['a', 'b'], node.rassoc('b')) }
92
- it('#to_h') { assert_equal({'a' => 'b', 'c' => node['c']}, node.to_h) }
93
- it('#to_proc') { assert_equal('b', node.to_proc.call('a')) } if {}.respond_to?(:to_proc)
94
- if {}.respond_to?(:transform_values)
95
- it('#transform_values') { assert_equal({'a' => nil, 'c' => nil}, node.transform_values { |_| nil}) }
89
+ describe 'key + value methods' do
90
+ it('#<') { assert_equal(true, node < {'a' => 'b', 'c' => node['c'], 'x' => 'y'}) } if {}.respond_to?(:<)
91
+ it('#<=') { assert_equal(true, node <= node) } if {}.respond_to?(:<=)
92
+ it('#>') { assert_equal(true, node > {}) } if {}.respond_to?(:>)
93
+ it('#>=') { assert_equal(false, node >= {'foo' => 'bar'}) } if {}.respond_to?(:>=)
94
+ it('#any?') { assert_equal(false, node.any? { |k, v| v == 3 }) }
95
+ it('#assoc') { assert_equal(['a', 'b'], node.assoc('a')) }
96
+ it('#dig') { assert_equal('e', node.dig('c', 'd')) } if {}.respond_to?(:dig)
97
+ it('#each_pair') { assert_equal([['a', 'b'], ['c', node['c']]], node.each_pair.to_a) }
98
+ it('#each_value') { assert_equal(['b', node['c']], node.each_value.to_a) }
99
+ it('#fetch') { assert_equal('b', node.fetch('a')) }
100
+ it('#fetch_values') { assert_equal(['b'], node.fetch_values('a')) } if {}.respond_to?(:fetch_values)
101
+ it('#has_value?') { assert_equal(true, node.has_value?('b')) }
102
+ it('#invert') { assert_equal({'b' => 'a', node['c'] => 'c'}, node.invert) }
103
+ it('#key') { assert_equal('a', node.key('b')) }
104
+ it('#rassoc') { assert_equal(['a', 'b'], node.rassoc('b')) }
105
+ it('#to_h') { assert_equal({'a' => 'b', 'c' => node['c']}, node.to_h) }
106
+ it('#to_proc') { assert_equal('b', node.to_proc.call('a')) } if {}.respond_to?(:to_proc)
107
+ if {}.respond_to?(:transform_values)
108
+ it('#transform_values') { assert_equal({'a' => nil, 'c' => nil}, node.transform_values { |_| nil }) }
109
+ end
110
+ it('#value?') { assert_equal(false, node.value?('0')) }
111
+ it('#values') { assert_equal(['b', node['c']], node.values) }
112
+ it('#values_at') { assert_equal(['b'], node.values_at('a')) }
96
113
  end
97
- it('#value?') { assert_equal(false, node.value?('0')) }
98
- it('#values') { assert_equal(['b', node['c']], node.values) }
99
- it('#values_at') { assert_equal(['b'], node.values_at('a')) }
100
- end
101
- describe 'modified copy methods' do
102
- # I'm going to rely on the #merge test above to test the modified copy functionality and just do basic
103
- # tests of all the modified copy methods here
104
- it('#merge') { assert_equal(node, node.merge({})) }
105
- it('#reject') { assert_equal(JSI::JSON::Node.new_by_type({}, []), node.reject { true }) }
106
- it('#select') { assert_equal(JSI::JSON::Node.new_by_type({}, []), node.select { false }) }
107
- # Hash#compact only available as of ruby 2.5.0
108
- if {}.respond_to?(:compact)
109
- it('#compact') { assert_equal(node, node.compact) }
114
+ describe 'modified copy methods' do
115
+ # I'm going to rely on the #merge test above to test the modified copy functionality and just do basic
116
+ # tests of all the modified copy methods here
117
+ it('#merge') { assert_equal(JSI::JSON::Node.new_doc(node.content.to_hash), node.merge({})) }
118
+ it('#reject') { assert_equal(JSI::JSON::Node.new_doc({}), node.reject { true }) }
119
+ it('#select') { assert_equal(JSI::JSON::Node.new_doc({}), node.select { false }) }
120
+ # Hash#compact only available as of ruby 2.5.0
121
+ if {}.respond_to?(:compact)
122
+ it('#compact') { assert_equal(JSI::JSON::Node.new_doc({"a" => "b", "c" => node.content.to_hash["c"]}), node.compact) }
123
+ end
110
124
  end
111
- end
112
- JSI::Hashlike::DESTRUCTIVE_METHODS.each do |destructive_method_name|
113
- it("does not respond to destructive method #{destructive_method_name}") do
114
- assert(!node.respond_to?(destructive_method_name))
125
+ JSI::Hashlike::DESTRUCTIVE_METHODS.each do |destructive_method_name|
126
+ it("does not respond to destructive method #{destructive_method_name}") do
127
+ assert(!node.respond_to?(destructive_method_name))
128
+ end
115
129
  end
116
130
  end
117
131
  end
@@ -13,18 +13,18 @@ describe JSI::JSON::Node do
13
13
  end
14
14
  describe 'initialization by .new_by_type' do
15
15
  it 'initializes HashNode' do
16
- node = JSI::JSON::Node.new_by_type({'a' => 'b'}, [])
16
+ node = JSI::JSON::Node.new_doc({'a' => 'b'})
17
17
  assert_instance_of(JSI::JSON::HashNode, node)
18
18
  assert_equal({'a' => 'b'}, node.document)
19
19
  end
20
20
  it 'initializes ArrayNode' do
21
- node = JSI::JSON::Node.new_by_type(['a', 'b'], [])
21
+ node = JSI::JSON::Node.new_doc(['a', 'b'])
22
22
  assert_instance_of(JSI::JSON::ArrayNode, node)
23
23
  assert_equal(['a', 'b'], node.document)
24
24
  end
25
25
  it 'initializes Node' do
26
26
  object = Object.new
27
- node = JSI::JSON::Node.new_by_type(object, [])
27
+ node = JSI::JSON::Node.new_doc(object)
28
28
  assert_instance_of(JSI::JSON::Node, node)
29
29
  assert_equal(object, node.document)
30
30
  end
@@ -261,22 +261,22 @@ describe JSI::JSON::Node do
261
261
  assert_equal('x', {JSI::JSON::Node.new([0], []) => 'x'}[JSI::JSON::Node.new([0], [])])
262
262
  end
263
263
  it 'hashes consistently regardless of the Node being decorated as a subclass' do
264
- assert_equal('x', {JSI::JSON::Node.new_by_type([0], []) => 'x'}[JSI::JSON::Node.new([0], [])])
265
- assert_equal('x', {JSI::JSON::Node.new([0], []) => 'x'}[JSI::JSON::Node.new_by_type([0], [])])
264
+ assert_equal('x', {JSI::JSON::Node.new_doc([0]) => 'x'}[JSI::JSON::Node.new([0], [])])
265
+ assert_equal('x', {JSI::JSON::Node.new([0], []) => 'x'}[JSI::JSON::Node.new_doc([0])])
266
266
  end
267
267
  it '==' do
268
268
  assert_equal(JSI::JSON::Node.new([0], []), JSI::JSON::Node.new([0], []))
269
- assert_equal(JSI::JSON::Node.new_by_type([0], []), JSI::JSON::Node.new([0], []))
270
- assert_equal(JSI::JSON::Node.new([0], []), JSI::JSON::Node.new_by_type([0], []))
271
- assert_equal(JSI::JSON::Node.new_by_type([0], []), JSI::JSON::Node.new_by_type([0], []))
269
+ assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new([0], []))
270
+ assert_equal(JSI::JSON::Node.new([0], []), JSI::JSON::Node.new_doc([0]))
271
+ assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc([0]))
272
272
  end
273
273
  it '!=' do
274
274
  refute_equal(JSI::JSON::Node.new([0], []), JSI::JSON::Node.new({}, []))
275
- refute_equal(JSI::JSON::Node.new_by_type([0], []), JSI::JSON::Node.new({}, []))
276
- refute_equal(JSI::JSON::Node.new([0], []), JSI::JSON::Node.new_by_type({}, []))
277
- refute_equal(JSI::JSON::Node.new_by_type([0], []), JSI::JSON::Node.new_by_type({}, []))
278
- refute_equal({}, JSI::JSON::Node.new_by_type({}, []))
279
- refute_equal(JSI::JSON::Node.new_by_type({}, []), {})
275
+ refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new({}, []))
276
+ refute_equal(JSI::JSON::Node.new([0], []), JSI::JSON::Node.new_doc({}))
277
+ refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc({}))
278
+ refute_equal({}, JSI::JSON::Node.new_doc({}))
279
+ refute_equal(JSI::JSON::Node.new_doc({}), {})
280
280
  end
281
281
  end
282
282
  describe '#as_json' do
@@ -10,7 +10,7 @@ describe JSI::SchemaInstanceJSONCoder do
10
10
  assert_nil(schema_instance_json_coder.load(nil))
11
11
  end
12
12
  it 'loads a hash' do
13
- assert_equal(schema_instance_class.new(foo: 'bar'), schema_instance_json_coder.load({"foo" => "bar"}))
13
+ assert_equal(schema_instance_class.new('foo' => 'bar'), schema_instance_json_coder.load({"foo" => "bar"}))
14
14
  end
15
15
  it 'loads something else' do
16
16
  assert_equal(schema_instance_class.new([[]]), schema_instance_json_coder.load([[]]))
@@ -19,7 +19,7 @@ describe JSI::SchemaInstanceJSONCoder do
19
19
  let(:options) { {array: true} }
20
20
  it 'loads an array of hashes' do
21
21
  data = [{"foo" => "bar"}, {"foo" => "baz"}]
22
- assert_equal([schema_instance_class.new(foo: 'bar'), schema_instance_class.new(foo: 'baz')], schema_instance_json_coder.load(data))
22
+ assert_equal([schema_instance_class.new('foo' => 'bar'), schema_instance_class.new('foo' => 'baz')], schema_instance_json_coder.load(data))
23
23
  end
24
24
  it 'loads an empty array' do
25
25
  assert_equal([], schema_instance_json_coder.load([]))
@@ -36,7 +36,7 @@ describe JSI::SchemaInstanceJSONCoder do
36
36
  assert_nil(schema_instance_json_coder.dump(nil))
37
37
  end
38
38
  it 'dumps a schema_instance_class' do
39
- assert_equal({"foo" => "x","bar" => "y"}, schema_instance_json_coder.dump(schema_instance_class.new(foo: 'x', bar: 'y')))
39
+ assert_equal({"foo" => "x", "bar" => "y"}, schema_instance_json_coder.dump(schema_instance_class.new(foo: 'x', bar: 'y')))
40
40
  end
41
41
  it 'dumps something else' do
42
42
  assert_raises(TypeError) do
@@ -53,7 +53,7 @@ describe JSI::SchemaInstanceJSONCoder do
53
53
  let(:options) { {array: true} }
54
54
  it 'dumps an array of schema_instances' do
55
55
  schema_instances = [schema_instance_class.new(foo: 'x', bar: 'y'), schema_instance_class.new(foo: 'z', bar: 'q')]
56
- assert_equal([{"foo" => "x","bar" => "y"},{"foo" => "z","bar" => "q"}], schema_instance_json_coder.dump(schema_instances))
56
+ assert_equal([{"foo" => "x", "bar" => "y"}, {"foo" => "z", "bar" => "q"}], schema_instance_json_coder.dump(schema_instances))
57
57
  end
58
58
  end
59
59
  end
@@ -65,7 +65,7 @@ describe JSI::SchemaInstanceJSONCoder do
65
65
  assert_nil(schema_instance_json_coder.load(nil))
66
66
  end
67
67
  it 'loads a hash' do
68
- assert_equal(schema_instance_class.new(foo: 'bar'), schema_instance_json_coder.load('{"foo": "bar"}'))
68
+ assert_equal(schema_instance_class.new('foo' => 'bar'), schema_instance_json_coder.load('{"foo": "bar"}'))
69
69
  end
70
70
  it 'loads something else' do
71
71
  assert_equal(schema_instance_class.new([[]]), schema_instance_json_coder.load('[[]]'))
@@ -79,7 +79,7 @@ describe JSI::SchemaInstanceJSONCoder do
79
79
  let(:options) { {string: true, array: true} }
80
80
  it 'loads an array of hashes' do
81
81
  data = '[{"foo": "bar"}, {"foo": "baz"}]'
82
- assert_equal([schema_instance_class.new(foo: 'bar'), schema_instance_class.new(foo: 'baz')], schema_instance_json_coder.load(data))
82
+ assert_equal([schema_instance_class.new('foo' => 'bar'), schema_instance_class.new('foo' => 'baz')], schema_instance_json_coder.load(data))
83
83
  end
84
84
  it 'loads an empty array' do
85
85
  assert_equal([], schema_instance_json_coder.load('[]'))
@@ -118,5 +118,4 @@ describe JSI::SchemaInstanceJSONCoder do
118
118
  end
119
119
  end
120
120
  end
121
-
122
121
  end
@@ -0,0 +1,196 @@
1
+ require_relative 'test_helper'
2
+
3
+ SomeMetaschema = JSI.class_for_schema({id: 'https://schemas.jsi.unth.net/test/somemetaschema', type: 'object'})
4
+
5
+ describe JSI::Schema do
6
+ describe 'new' do
7
+ it 'initializes from a hash' do
8
+ schema = JSI::Schema.new({'type' => 'object'})
9
+ assert_equal(JSI::JSON::Node.new_doc({'type' => 'object'}), schema.schema_node)
10
+ end
11
+ it 'initializes from a Node' do
12
+ schema_node = JSI::JSON::Node.new_doc({'type' => 'object'})
13
+ schema = JSI::Schema.new(schema_node)
14
+ assert_equal(schema_node, schema.schema_node)
15
+ assert_equal(schema_node, schema.schema_object)
16
+ end
17
+ it 'initializes from a JSI' do
18
+ schema_jsi = SomeMetaschema.new('type' => 'object')
19
+ schema = JSI::Schema.new(schema_jsi)
20
+ assert_equal(schema_jsi.instance, schema.schema_node)
21
+ assert_equal(schema_jsi, schema.schema_object)
22
+ end
23
+ it 'cannot instantiate from some unknown object' do
24
+ err = assert_raises(TypeError) { JSI::Schema.new(Object.new) }
25
+ assert_match(/\Acannot instantiate Schema from: #<Object:.*>\z/m, err.message)
26
+ end
27
+ it 'makes no sense to instantiate schema from schema' do
28
+ err = assert_raises(TypeError) { JSI::Schema.new(JSI::Schema.new({})) }
29
+ assert_match(/\Awill not instantiate Schema from another Schema: #<JSI::Schema schema_id=.*>\z/m, err.message)
30
+ end
31
+ end
32
+ describe 'as an instance of metaschema' do
33
+ let(:default_metaschema) do
34
+ validator = ::JSON::Validator.default_validator
35
+ metaschema_file = validator.metaschema
36
+ JSI::Schema.new(::JSON.parse(File.read(metaschema_file)))
37
+ end
38
+ let(:metaschema_jsi_class) { JSI.class_for_schema(default_metaschema) }
39
+ let(:schema_object) { {'type' => 'array', 'items' => {'description' => 'items!'}} }
40
+ let(:schema_jsi) { metaschema_jsi_class.new(schema_object) }
41
+ let(:schema) { JSI::Schema.new(schema_jsi) }
42
+ it '#[]' do
43
+ schema_items = schema['items']
44
+ assert_instance_of(metaschema_jsi_class, schema_items)
45
+ assert_equal({'description' => 'items!'}, schema_items.as_json)
46
+ end
47
+ end
48
+ describe '#schema_id' do
49
+ it 'generates one' do
50
+ assert_match(/\A[0-9a-f\-]+#\z/, JSI::Schema.new({}).schema_id)
51
+ end
52
+ it 'uses a given id with a fragment' do
53
+ schema = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/given_id#'})
54
+ assert_equal('https://schemas.jsi.unth.net/test/given_id#', schema.schema_id)
55
+ end
56
+ it 'uses a given id (adding a fragment)' do
57
+ schema = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/given_id'})
58
+ assert_equal('https://schemas.jsi.unth.net/test/given_id#', schema.schema_id)
59
+ end
60
+ it 'uses a pointer in the fragment' do
61
+ schema_node = JSI::JSON::Node.new_doc({
62
+ 'id' => 'https://schemas.jsi.unth.net/test/given_id#',
63
+ 'properties' => {'foo' => {'type' => 'object'}},
64
+ })
65
+ schema = JSI::Schema.new(schema_node['properties']['foo'])
66
+ assert_equal('https://schemas.jsi.unth.net/test/given_id#/properties/foo', schema.schema_id)
67
+ end
68
+ it 'uses a pointer in the fragment relative to the fragment of the root' do
69
+ schema_node = JSI::JSON::Node.new_doc({
70
+ 'id' => 'https://schemas.jsi.unth.net/test/given_id#/notroot',
71
+ 'properties' => {'foo' => {'type' => 'object'}},
72
+ })
73
+ schema = JSI::Schema.new(schema_node['properties']['foo'])
74
+ assert_equal('https://schemas.jsi.unth.net/test/given_id#/notroot/properties/foo', schema.schema_id)
75
+ end
76
+ end
77
+ describe '#schema_class' do
78
+ it 'returns the class for the schema' do
79
+ schema_node = JSI::JSON::Node.new_doc({'id' => 'https://schemas.jsi.unth.net/test/schema_schema_class'})
80
+ assert_equal(JSI.class_for_schema(schema_node), JSI::Schema.new(schema_node).schema_class)
81
+ end
82
+ end
83
+ describe '#subschema_for_property' do
84
+ let(:schema) do
85
+ JSI::Schema.new({
86
+ properties: {foo: {description: 'foo'}},
87
+ patternProperties: {"^ba" => {description: 'ba*'}},
88
+ additionalProperties: {description: 'whatever'},
89
+ })
90
+ end
91
+ it 'has no subschema' do
92
+ assert_equal(nil, JSI::Schema.new({}).subschema_for_property('no'))
93
+ end
94
+ it 'has a subschema by property' do
95
+ subschema = schema.subschema_for_property('foo')
96
+ assert_instance_of(JSI::Schema, subschema)
97
+ assert_equal('foo', subschema['description'])
98
+ end
99
+ it 'has a subschema by pattern property' do
100
+ subschema = schema.subschema_for_property('bar')
101
+ assert_instance_of(JSI::Schema, subschema)
102
+ assert_equal('ba*', subschema['description'])
103
+ end
104
+ it 'has a subschema by additional properties' do
105
+ subschema = schema.subschema_for_property('anything')
106
+ assert_instance_of(JSI::Schema, subschema)
107
+ assert_equal('whatever', subschema['description'])
108
+ end
109
+ end
110
+ describe '#subschema_for_index' do
111
+ it 'has no subschema' do
112
+ assert_equal(nil, JSI::Schema.new({}).subschema_for_index(0))
113
+ end
114
+ it 'has a subschema for items' do
115
+ schema = JSI::Schema.new({
116
+ items: {description: 'items!'}
117
+ })
118
+ first_subschema = schema.subschema_for_index(0)
119
+ assert_instance_of(JSI::Schema, first_subschema)
120
+ assert_equal('items!', first_subschema['description'])
121
+ last_subschema = schema.subschema_for_index(1)
122
+ assert_instance_of(JSI::Schema, last_subschema)
123
+ assert_equal('items!', last_subschema['description'])
124
+ end
125
+ it 'has a subschema for each item by index' do
126
+ schema = JSI::Schema.new({
127
+ items: [{description: 'item one'}, {description: 'item two'}]
128
+ })
129
+ first_subschema = schema.subschema_for_index(0)
130
+ assert_instance_of(JSI::Schema, first_subschema)
131
+ assert_equal('item one', first_subschema['description'])
132
+ last_subschema = schema.subschema_for_index(1)
133
+ assert_instance_of(JSI::Schema, last_subschema)
134
+ assert_equal('item two', last_subschema['description'])
135
+ end
136
+ it 'has a subschema by additional items' do
137
+ schema = JSI::Schema.new({
138
+ items: [{description: 'item one'}],
139
+ additionalItems: {description: "mo' crap"},
140
+ })
141
+ first_subschema = schema.subschema_for_index(0)
142
+ assert_instance_of(JSI::Schema, first_subschema)
143
+ assert_equal('item one', first_subschema['description'])
144
+ last_subschema = schema.subschema_for_index(1)
145
+ assert_instance_of(JSI::Schema, last_subschema)
146
+ assert_equal("mo' crap", last_subschema['description'])
147
+ end
148
+ end
149
+ describe 'stringification' do
150
+ let(:schema) do
151
+ JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/stringification', type: 'object'})
152
+ end
153
+
154
+ it '#inspect' do
155
+ assert_equal(%q(#<JSI::Schema schema_id=https://schemas.jsi.unth.net/test/stringification# #{<JSI::JSON::HashNode fragment="#"> "id" => "https://schemas.jsi.unth.net/test/stringification", "type" => "object"}>), schema.inspect)
156
+ end
157
+ it '#pretty_print' do
158
+ assert_equal(%q(#<JSI::Schema schema_id=https://schemas.jsi.unth.net/test/stringification#
159
+ #{<JSI::JSON::HashNode fragment="#">
160
+ "id" => "https://schemas.jsi.unth.net/test/stringification",
161
+ "type" => "object"
162
+ }
163
+ >).gsub(/^ /, ''), schema.pretty_inspect.chomp)
164
+ end
165
+ end
166
+ describe 'validation' do
167
+ let(:schema) { JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/validation', type: 'object'}) }
168
+ describe 'without errors' do
169
+ let(:instance) { {'foo' => 'bar'} }
170
+ it '#fully_validate' do
171
+ assert_equal([], schema.fully_validate(instance))
172
+ end
173
+ it '#validate' do
174
+ assert_equal(true, schema.validate(instance))
175
+ end
176
+ it '#validate!' do
177
+ assert_equal(true, schema.validate!(instance))
178
+ end
179
+ end
180
+ describe 'with errors' do
181
+ let(:instance) { ['no'] }
182
+ it '#fully_validate' do
183
+ assert_equal(["The property '#/' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/validation"], schema.fully_validate(instance))
184
+ end
185
+ it '#validate' do
186
+ assert_equal(false, schema.validate(instance))
187
+ end
188
+ it '#validate!' do
189
+ err = assert_raises(JSON::Schema::ValidationError) do
190
+ schema.validate!(instance)
191
+ end
192
+ assert_equal("The property '#/' of type array did not match the following type: object", err.message)
193
+ end
194
+ end
195
+ end
196
+ end