jsi 0.4.0 → 0.7.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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +33 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +114 -42
  6. data/jsi.gemspec +14 -12
  7. data/lib/jsi/base/node.rb +183 -0
  8. data/lib/jsi/base.rb +388 -220
  9. data/lib/jsi/jsi_coder.rb +8 -7
  10. data/lib/jsi/metaschema.rb +0 -1
  11. data/lib/jsi/metaschema_node/bootstrap_schema.rb +101 -0
  12. data/lib/jsi/metaschema_node.rb +159 -135
  13. data/lib/jsi/ptr.rb +303 -0
  14. data/lib/jsi/schema/application/child_application/contains.rb +25 -0
  15. data/lib/jsi/schema/application/child_application/draft04.rb +22 -0
  16. data/lib/jsi/schema/application/child_application/draft06.rb +29 -0
  17. data/lib/jsi/schema/application/child_application/draft07.rb +29 -0
  18. data/lib/jsi/schema/application/child_application/items.rb +18 -0
  19. data/lib/jsi/schema/application/child_application/properties.rb +25 -0
  20. data/lib/jsi/schema/application/child_application.rb +38 -0
  21. data/lib/jsi/schema/application/draft04.rb +8 -0
  22. data/lib/jsi/schema/application/draft06.rb +8 -0
  23. data/lib/jsi/schema/application/draft07.rb +8 -0
  24. data/lib/jsi/schema/application/inplace_application/dependencies.rb +28 -0
  25. data/lib/jsi/schema/application/inplace_application/draft04.rb +26 -0
  26. data/lib/jsi/schema/application/inplace_application/draft06.rb +27 -0
  27. data/lib/jsi/schema/application/inplace_application/draft07.rb +33 -0
  28. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +20 -0
  29. data/lib/jsi/schema/application/inplace_application/ref.rb +18 -0
  30. data/lib/jsi/schema/application/inplace_application/someof.rb +44 -0
  31. data/lib/jsi/schema/application/inplace_application.rb +41 -0
  32. data/lib/jsi/schema/application.rb +12 -0
  33. data/lib/jsi/schema/draft04.rb +14 -0
  34. data/lib/jsi/schema/draft06.rb +14 -0
  35. data/lib/jsi/schema/draft07.rb +14 -0
  36. data/lib/jsi/schema/issue.rb +36 -0
  37. data/lib/jsi/schema/ref.rb +160 -0
  38. data/lib/jsi/schema/schema_ancestor_node.rb +113 -0
  39. data/lib/jsi/schema/validation/array.rb +69 -0
  40. data/lib/jsi/schema/validation/const.rb +20 -0
  41. data/lib/jsi/schema/validation/contains.rb +25 -0
  42. data/lib/jsi/schema/validation/core.rb +39 -0
  43. data/lib/jsi/schema/validation/dependencies.rb +49 -0
  44. data/lib/jsi/schema/validation/draft04/minmax.rb +91 -0
  45. data/lib/jsi/schema/validation/draft04.rb +112 -0
  46. data/lib/jsi/schema/validation/draft06.rb +122 -0
  47. data/lib/jsi/schema/validation/draft07.rb +159 -0
  48. data/lib/jsi/schema/validation/enum.rb +25 -0
  49. data/lib/jsi/schema/validation/ifthenelse.rb +46 -0
  50. data/lib/jsi/schema/validation/items.rb +54 -0
  51. data/lib/jsi/schema/validation/not.rb +20 -0
  52. data/lib/jsi/schema/validation/numeric.rb +121 -0
  53. data/lib/jsi/schema/validation/object.rb +45 -0
  54. data/lib/jsi/schema/validation/pattern.rb +34 -0
  55. data/lib/jsi/schema/validation/properties.rb +101 -0
  56. data/lib/jsi/schema/validation/property_names.rb +32 -0
  57. data/lib/jsi/schema/validation/ref.rb +40 -0
  58. data/lib/jsi/schema/validation/required.rb +27 -0
  59. data/lib/jsi/schema/validation/someof.rb +90 -0
  60. data/lib/jsi/schema/validation/string.rb +47 -0
  61. data/lib/jsi/schema/validation/type.rb +49 -0
  62. data/lib/jsi/schema/validation.rb +51 -0
  63. data/lib/jsi/schema.rb +508 -149
  64. data/lib/jsi/schema_classes.rb +199 -59
  65. data/lib/jsi/schema_registry.rb +151 -0
  66. data/lib/jsi/schema_set.rb +181 -0
  67. data/lib/jsi/simple_wrap.rb +23 -4
  68. data/lib/jsi/util/private/attr_struct.rb +127 -0
  69. data/lib/jsi/util/private.rb +204 -0
  70. data/lib/jsi/util/typelike.rb +229 -0
  71. data/lib/jsi/util.rb +89 -53
  72. data/lib/jsi/validation/error.rb +34 -0
  73. data/lib/jsi/validation/result.rb +210 -0
  74. data/lib/jsi/validation.rb +15 -0
  75. data/lib/jsi/version.rb +3 -1
  76. data/lib/jsi.rb +44 -14
  77. data/lib/schemas/json-schema.org/draft-04/schema.rb +10 -3
  78. data/lib/schemas/json-schema.org/draft-06/schema.rb +10 -3
  79. data/lib/schemas/json-schema.org/draft-07/schema.rb +14 -0
  80. data/readme.rb +138 -0
  81. data/{resources}/schemas/json-schema.org/draft-04/schema.json +149 -0
  82. data/{resources}/schemas/json-schema.org/draft-06/schema.json +154 -0
  83. data/{resources}/schemas/json-schema.org/draft-07/schema.json +168 -0
  84. metadata +75 -122
  85. data/.simplecov +0 -3
  86. data/Rakefile.rb +0 -9
  87. data/lib/jsi/base/to_rb.rb +0 -128
  88. data/lib/jsi/json/node.rb +0 -203
  89. data/lib/jsi/json/pointer.rb +0 -419
  90. data/lib/jsi/json-schema-fragments.rb +0 -61
  91. data/lib/jsi/json.rb +0 -10
  92. data/lib/jsi/pathed_node.rb +0 -118
  93. data/lib/jsi/typelike_modules.rb +0 -240
  94. data/resources/icons/AGPL-3.0.png +0 -0
  95. data/test/base_array_test.rb +0 -323
  96. data/test/base_hash_test.rb +0 -337
  97. data/test/base_test.rb +0 -486
  98. data/test/jsi_coder_test.rb +0 -85
  99. data/test/jsi_json_arraynode_test.rb +0 -150
  100. data/test/jsi_json_hashnode_test.rb +0 -132
  101. data/test/jsi_json_node_test.rb +0 -257
  102. data/test/jsi_json_pointer_test.rb +0 -102
  103. data/test/jsi_test.rb +0 -11
  104. data/test/jsi_typelike_as_json_test.rb +0 -53
  105. data/test/metaschema_node_test.rb +0 -19
  106. data/test/schema_module_test.rb +0 -21
  107. data/test/schema_test.rb +0 -208
  108. data/test/spreedly_openapi_test.rb +0 -8
  109. data/test/test_helper.rb +0 -97
  110. data/test/util_test.rb +0 -62
@@ -1,150 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- document_types = [
4
- {
5
- make_document: -> (d) { d },
6
- node_document: ['a', ['b', 'q'], {'c' => {'d' => 'e'}}],
7
- type_desc: 'Array',
8
- },
9
- {
10
- make_document: -> (d) { SortOfArray.new(d) },
11
- node_document: SortOfArray.new(['a', SortOfArray.new(['b', 'q']), SortOfHash.new({'c' => SortOfHash.new({'d' => 'e'})})]),
12
- type_desc: 'sort of Array-like',
13
- },
14
- ]
15
- document_types.each do |document_type|
16
- describe "JSI::JSON::ArrayNode with #{document_type[:type_desc]}" do
17
- # node_document of the node being tested
18
- let(:node_document) { document_type[:node_document] }
19
- # by default the node is the whole document
20
- let(:path) { [] }
21
- let(:node_ptr) { JSI::JSON::Pointer.new(path) }
22
- # the node being tested
23
- let(:node) { JSI::JSON::Node.new_by_type(node_document, node_ptr) }
24
-
25
- describe '#[] bad index' do
26
- it 'improves TypeError for Array subsript' do
27
- err = assert_raises(TypeError) do
28
- node[:x]
29
- end
30
- assert_match(/^subscripting with :x \(Symbol\) from Array. content is: \[.*\]\z/m, err.message)
31
- end
32
- end
33
- describe '#each' do
34
- it 'iterates, one argument' do
35
- out = []
36
- node.each do |arg|
37
- out << arg
38
- end
39
- assert_instance_of(JSI::JSON::ArrayNode, node[1])
40
- assert_instance_of(JSI::JSON::HashNode, node[2])
41
- assert_equal(['a', node[1], node[2]], out)
42
- end
43
- it 'returns self' do
44
- assert_equal(node.each { }.object_id, node.object_id)
45
- end
46
- it 'returns an enumerator when called with no block' do
47
- enum = node.each
48
- assert_instance_of(Enumerator, enum)
49
- assert_equal(['a', node[1], node[2]], enum.to_a)
50
- end
51
- end
52
- describe '#to_ary' do
53
- it 'returns a Array with Nodes in' do
54
- assert_instance_of(Array, node.to_ary)
55
- assert_equal(['a', node[1], node[2]], node.to_ary)
56
- end
57
- end
58
- describe '#as_json' do
59
- let(:node_document) { document_type[:make_document].call(['a', 'b']) }
60
- it '#as_json' do
61
- assert_equal(['a', 'b'], node.as_json)
62
- assert_equal(['a', 'b'], node.as_json(some_option: false))
63
- end
64
- end
65
- # these methods just delegate to Array so not going to test excessively
66
- describe 'index only methods' do
67
- it('#each_index') { assert_equal([0, 1, 2], node.each_index.to_a) }
68
- it('#empty?') { assert_equal(false, node.empty?) }
69
- it('#length') { assert_equal(3, node.length) }
70
- it('#size') { assert_equal(3, node.size) }
71
- end
72
- describe 'index + element methods' do
73
- it('#|') { assert_equal(['a', node[1], node[2], 0], node | [0]) }
74
- it('#&') { assert_equal(['a'], node & ['a']) }
75
- it('#*') { assert_equal(node.to_a, node * 1) }
76
- it('#+') { assert_equal(node.to_a, node + []) }
77
- it('#-') { assert_equal([node[1], node[2]], node - ['a']) }
78
- it('#<=>') { assert_equal(1, node <=> []) }
79
- it('#<=>') { assert_equal(-1, [] <=> node) }
80
- require 'abbrev'
81
- it('#abbrev') { assert_equal({'a' => 'a'}, JSI::JSON::Node.new_doc(['a']).abbrev) }
82
- it('#assoc') { assert_equal(['b', 'q'], node.assoc('b')) }
83
- it('#at') { assert_equal('a', node.at(0)) }
84
- it('#bsearch') { assert_equal(nil, node.bsearch { false }) }
85
- it('#bsearch_index') { assert_equal(nil, node.bsearch_index { false }) } if [].respond_to?(:bsearch_index)
86
- it('#combination') { assert_equal([['a'], [node[1]], [node[2]]], node.combination(1).to_a) }
87
- it('#count') { assert_equal(1, node.count('a')) }
88
- it('#cycle') { assert_equal(node.to_a, node.cycle(1).to_a) }
89
- it('#dig') { assert_equal('e', node.dig(2, 'c', 'd')) } if [].respond_to?(:dig)
90
- it('#drop') { assert_equal([node[2]], node.drop(2)) }
91
- it('#drop_while') { assert_equal([node[1], node[2]], node.drop_while { |e| e == 'a' }) }
92
- it('#fetch') { assert_equal('a', node.fetch(0)) }
93
- it('#find_index') { assert_equal(0, node.find_index { true }) }
94
- it('#first') { assert_equal('a', node.first) }
95
- it('#include?') { assert_equal(true, node.include?('a')) }
96
- it('#index') { assert_equal(0, node.index('a')) }
97
- it('#join') { assert_equal('a b', JSI::JSON::Node.new_doc(['a', 'b']).join(' ')) }
98
- it('#last') { assert_equal(node[2], node.last) }
99
- it('#pack') { assert_equal(' ', JSI::JSON::Node.new_doc([32]).pack('c')) }
100
- it('#permutation') { assert_equal([['a'], [node[1]], [node[2]]], node.permutation(1).to_a) }
101
- it('#product') { assert_equal([], node.product([])) }
102
- # due to differences in implementation between #assoc and #rassoc, the reason for which
103
- # I cannot begin to fathom, assoc works but rassoc does not because rassoc has different
104
- # type checking than assoc for the array(like) array elements.
105
- # compare:
106
- # assoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3780-L3813
107
- # rassoc: https://github.com/ruby/ruby/blob/v2_5_0/array.c#L3815-L3847
108
- # for this reason, rassoc is NOT defined on Arraylike. it's here with as_json.
109
- #
110
- # I've never even seen anybody use rassoc. of all the methods to put into the standard library ...
111
- it('#rassoc') { assert_equal(['b', 'q'], node.as_json.rassoc('q')) }
112
- it('#repeated_combination') { assert_equal([[]], node.repeated_combination(0).to_a) }
113
- it('#repeated_permutation') { assert_equal([[]], node.repeated_permutation(0).to_a) }
114
- it('#reverse') { assert_equal([node[2], node[1], 'a'], node.reverse) }
115
- it('#reverse_each') { assert_equal([node[2], node[1], 'a'], node.reverse_each.to_a) }
116
- it('#rindex') { assert_equal(0, node.rindex('a')) }
117
- it('#rotate') { assert_equal([node[1], node[2], 'a'], node.rotate) }
118
- it('#sample') { assert_equal('a', JSI::JSON::Node.new_doc(['a']).sample) }
119
- it('#shelljoin') { assert_equal('a', JSI::JSON::Node.new_doc(['a']).shelljoin) } if [].respond_to?(:shelljoin)
120
- it('#shuffle') { assert_equal(3, node.shuffle.size) }
121
- it('#slice') { assert_equal(['a'], node.slice(0, 1)) }
122
- it('#sort') { assert_equal(['a'], JSI::JSON::Node.new_doc(['a']).sort) }
123
- it('#take') { assert_equal(['a'], node.take(1)) }
124
- it('#take_while') { assert_equal([], node.take_while { false }) }
125
- it('#transpose') { assert_equal([], JSI::JSON::Node.new_doc([]).transpose) }
126
- it('#uniq') { assert_equal(node.to_a, node.uniq) }
127
- it('#values_at') { assert_equal(['a'], node.values_at(0)) }
128
- it('#zip') { assert_equal([['a', 'a'], [node[1], node[1]], [node[2], node[2]]], node.zip(node)) }
129
- end
130
- describe 'modified copy methods' do
131
- it('#reject') { assert_equal(JSI::JSON::Node.new_doc(['a']), node.reject { |e| e != 'a' }) }
132
- it('#select') { assert_equal(JSI::JSON::Node.new_doc(['a']), node.select { |e| e == 'a' }) }
133
- it('#compact') { assert_equal(JSI::JSON::Node.new_doc(node.node_content.to_ary), node.compact) }
134
- describe 'at a depth' do
135
- let(:node_document) { document_type[:make_document].call([['b', 'q'], {'c' => ['d', 'e']}]) }
136
- let(:path) { ['1', 'c'] }
137
- it('#select') do
138
- selected = node.select { |e| e == 'd' }
139
- equivalent = JSI::JSON::Node.new_by_type([['b', 'q'], {'c' => ['d']}], node_ptr)
140
- assert_equal(equivalent, selected)
141
- end
142
- end
143
- end
144
- JSI::Arraylike::DESTRUCTIVE_METHODS.each do |destructive_method_name|
145
- it("does not respond to destructive method #{destructive_method_name}") do
146
- assert(!node.respond_to?(destructive_method_name))
147
- end
148
- end
149
- end
150
- end
@@ -1,132 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- document_types = [
4
- {
5
- make_document: -> (d) { d },
6
- node_document: {'a' => 'b', 'c' => {'d' => 'e'}},
7
- type_desc: 'Hash',
8
- },
9
- {
10
- make_document: -> (d) { SortOfHash.new(d) },
11
- node_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
- # node_document of the node being tested
18
- let(:node_document) { document_type[:node_document] }
19
- # by default the node is the whole document
20
- let(:path) { [] }
21
- let(:node_ptr) { JSI::JSON::Pointer.new(path) }
22
- # the node being tested
23
- let(:node) { JSI::JSON::Node.new_by_type(node_document, node_ptr) }
24
-
25
- describe '#each' do
26
- it 'iterates, one argument' do
27
- out = []
28
- node.each do |arg|
29
- out << arg
30
- end
31
- assert_instance_of(JSI::JSON::HashNode, node['c'])
32
- assert_equal([['a', 'b'], ['c', node['c']]], out)
33
- end
34
- it 'iterates, two arguments' do
35
- out = []
36
- node.each do |k, v|
37
- out << [k, v]
38
- end
39
- assert_instance_of(JSI::JSON::HashNode, node['c'])
40
- assert_equal([['a', 'b'], ['c', node['c']]], out)
41
- end
42
- it 'returns self' do
43
- assert_equal(node.each { }.object_id, node.object_id)
44
- end
45
- it 'returns an enumerator when called with no block' do
46
- enum = node.each
47
- assert_instance_of(Enumerator, enum)
48
- assert_equal([['a', 'b'], ['c', node['c']]], enum.to_a)
49
- end
50
- end
51
- describe '#to_hash' do
52
- it 'returns a Hash with Nodes in' do
53
- assert_instance_of(Hash, node.to_hash)
54
- assert_equal({'a' => 'b', 'c' => node['c']}, node.to_hash)
55
- end
56
- end
57
- describe '#merge' do
58
- let(:node_document) { document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}) }
59
- # testing the node at 'c' here, merging a hash at a path within a document.
60
- let(:path) { ['c'] }
61
- it 'merges' do
62
- merged = node.merge('x' => 'y')
63
- # check the node_content at 'c' was merged with the remainder of the document intact (at 'a')
64
- assert_equal({'a' => {'b' => 0}, 'c' => {'d' => 'e', 'x' => 'y'}}, merged.node_document)
65
- # check the original node retains its original document
66
- assert_equal(document_type[:make_document].call({'a' => {'b' => 0}, 'c' => {'d' => 'e'}}), node.node_document)
67
- # check that unnecessary copies of unaffected parts of the document were not made
68
- assert_equal(node.node_document.to_hash['a'].object_id, merged.node_document['a'].object_id)
69
- end
70
- end
71
- describe '#as_json' do
72
- let(:node_document) { document_type[:make_document].call({'a' => 'b'}) }
73
- it '#as_json' do
74
- assert_equal({'a' => 'b'}, node.as_json)
75
- assert_equal({'a' => 'b'}, node.as_json(this_option: 'what?'))
76
- end
77
- end
78
- # these methods just delegate to Hash so not going to test excessively
79
- describe 'key only methods' do
80
- it('#each_key') { assert_equal(['a', 'c'], node.each_key.to_a) }
81
- it('#empty?') { assert_equal(false, node.empty?) }
82
- it('#has_key?') { assert_equal(true, node.has_key?('a')) }
83
- it('#include?') { assert_equal(false, node.include?('q')) }
84
- it('#key?') { assert_equal(true, node.key?('c')) }
85
- it('#keys') { assert_equal(['a', 'c'], node.keys) }
86
- it('#length') { assert_equal(2, node.length) }
87
- it('#member?') { assert_equal(false, node.member?(0)) }
88
- it('#size') { assert_equal(2, node.size) }
89
- end
90
- describe 'key + value methods' do
91
- it('#<') { assert_equal(true, node < {'a' => 'b', 'c' => node['c'], 'x' => 'y'}) } if {}.respond_to?(:<)
92
- it('#<=') { assert_equal(true, node <= node) } if {}.respond_to?(:<=)
93
- it('#>') { assert_equal(true, node > {}) } if {}.respond_to?(:>)
94
- it('#>=') { assert_equal(false, node >= {'foo' => 'bar'}) } if {}.respond_to?(:>=)
95
- it('#any?') { assert_equal(false, node.any? { |k, v| v == 3 }) }
96
- it('#assoc') { assert_equal(['a', 'b'], node.assoc('a')) }
97
- it('#dig') { assert_equal('e', node.dig('c', 'd')) } if {}.respond_to?(:dig)
98
- it('#each_pair') { assert_equal([['a', 'b'], ['c', node['c']]], node.each_pair.to_a) }
99
- it('#each_value') { assert_equal(['b', node['c']], node.each_value.to_a) }
100
- it('#fetch') { assert_equal('b', node.fetch('a')) }
101
- it('#fetch_values') { assert_equal(['b'], node.fetch_values('a')) } if {}.respond_to?(:fetch_values)
102
- it('#has_value?') { assert_equal(true, node.has_value?('b')) }
103
- it('#invert') { assert_equal({'b' => 'a', node['c'] => 'c'}, node.invert) }
104
- it('#key') { assert_equal('a', node.key('b')) }
105
- it('#rassoc') { assert_equal(['a', 'b'], node.rassoc('b')) }
106
- it('#to_h') { assert_equal({'a' => 'b', 'c' => node['c']}, node.to_h) }
107
- it('#to_proc') { assert_equal('b', node.to_proc.call('a')) } if {}.respond_to?(:to_proc)
108
- if {}.respond_to?(:transform_values)
109
- it('#transform_values') { assert_equal({'a' => nil, 'c' => nil}, node.transform_values { |_| nil }) }
110
- end
111
- it('#value?') { assert_equal(false, node.value?('0')) }
112
- it('#values') { assert_equal(['b', node['c']], node.values) }
113
- it('#values_at') { assert_equal(['b'], node.values_at('a')) }
114
- end
115
- describe 'modified copy methods' do
116
- # I'm going to rely on the #merge test above to test the modified copy functionality and just do basic
117
- # tests of all the modified copy methods here
118
- it('#merge') { assert_equal(JSI::JSON::Node.new_doc(node.node_content), node.merge({})) }
119
- it('#reject') { assert_equal(JSI::JSON::Node.new_doc({}), node.reject { true }) }
120
- it('#select') { assert_equal(JSI::JSON::Node.new_doc({}), node.select { false }) }
121
- # Hash#compact only available as of ruby 2.5.0
122
- if {}.respond_to?(:compact)
123
- it('#compact') { assert_equal(JSI::JSON::Node.new_doc({"a" => "b", "c" => node.node_content.to_hash["c"]}), node.compact) }
124
- end
125
- end
126
- JSI::Hashlike::DESTRUCTIVE_METHODS.each do |destructive_method_name|
127
- it("does not respond to destructive method #{destructive_method_name}") do
128
- assert(!node.respond_to?(destructive_method_name))
129
- end
130
- end
131
- end
132
- end
@@ -1,257 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe JSI::JSON::Node do
4
- let(:path) { [] }
5
- let(:node_ptr) { JSI::JSON::Pointer.new(path) }
6
- let(:node) { JSI::JSON::Node.new(node_document, node_ptr) }
7
-
8
- describe 'initialization' do
9
- it 'initializes' do
10
- node = JSI::JSON::Node.new({'a' => 'b'}, node_ptr)
11
- assert_equal({'a' => 'b'}, node.node_document)
12
- assert_equal(JSI::JSON::Pointer.new([]), node.node_ptr)
13
- end
14
- it 'initializes, node_ptr is not node_ptr' do
15
- err = assert_raises(TypeError) { JSI::JSON::Node.new({'a' => 'b'}, []) }
16
- assert_equal('node_ptr must be a JSI::JSON::Pointer. got: [] (Array)', err.message)
17
- end
18
- it 'initializes, node_document is another Node' do
19
- err = assert_raises(TypeError) { JSI::JSON::Node.new(JSI::JSON::Node.new({'a' => 'b'}, node_ptr), node_ptr) }
20
- assert_equal("node_document of a Node should not be another JSI::JSON::Node: #<JSI::JSON::Node # {\"a\"=>\"b\"}>", err.message)
21
- end
22
- end
23
- describe 'initialization by .new_by_type' do
24
- it 'initializes HashNode' do
25
- node = JSI::JSON::Node.new_doc({'a' => 'b'})
26
- assert_instance_of(JSI::JSON::HashNode, node)
27
- assert_equal({'a' => 'b'}, node.node_document)
28
- end
29
- it 'initializes ArrayNode' do
30
- node = JSI::JSON::Node.new_doc(['a', 'b'])
31
- assert_instance_of(JSI::JSON::ArrayNode, node)
32
- assert_equal(['a', 'b'], node.node_document)
33
- end
34
- it 'initializes Node' do
35
- object = Object.new
36
- node = JSI::JSON::Node.new_doc(object)
37
- assert_instance_of(JSI::JSON::Node, node)
38
- assert_equal(object, node.node_document)
39
- end
40
- end
41
- describe '#node_ptr' do
42
- it 'is a JSI::JSON::Pointer' do
43
- assert_instance_of(JSI::JSON::Pointer, JSI::JSON::Node.new({}, node_ptr).node_ptr)
44
- end
45
- end
46
- describe '#node_content' do
47
- it 'returns the node_content at the root' do
48
- assert_equal({'a' => 'b'}, JSI::JSON::Node.new({'a' => 'b'}, node_ptr).node_content)
49
- end
50
- it 'returns the node_content from the deep' do
51
- assert_equal('b', JSI::JSON::Node.new([0, {'x' => [{'a' => ['b']}]}], JSI::JSON::Pointer.new([1, 'x', 0, 'a', 0])).node_content)
52
- end
53
- end
54
- describe '#deref' do
55
- let(:node_document) do
56
- {
57
- 'foo' => {'bar' => ['baz']},
58
- 'a' => {'$ref' => '#/foo'},
59
- }
60
- end
61
- it 'follows a $ref' do
62
- assert_equal({'bar' => ['baz']}, node['a'].deref.node_content)
63
- end
64
- it 'returns the node when there is no $ref to follow' do
65
- assert_equal({'bar' => ['baz']}, node['foo'].deref.node_content)
66
- end
67
- describe "dealing with google's invalid $refs" do
68
- let(:node_document) do
69
- {
70
- 'schemas' => {'bar' => {'description' => ['baz']}},
71
- 'a' => {'$ref' => 'bar', 'foo' => 'bar'},
72
- }
73
- end
74
- it 'subscripts a node consisting of a $ref WITHOUT following' do
75
- subscripted = node['a']
76
- assert_equal({'$ref' => 'bar', 'foo' => 'bar'}, subscripted.node_content)
77
- assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.node_ptr)
78
- end
79
- it 'looks for a node in #/schemas with the name of the $ref' do
80
- assert_equal({'description' => ['baz']}, node['a'].deref.node_content)
81
- end
82
- end
83
- describe "dealing with whatever this is" do
84
- # I think google uses this style in some cases maybe. I don't remember.
85
- let(:node_document) do
86
- {
87
- 'schemas' => {'bar' => {'id' => 'BarID', 'description' => 'baz'}},
88
- 'a' => {'$ref' => 'BarID'},
89
- }
90
- end
91
- it 'looks for a node in #/schemas with the name of the $ref' do
92
- assert_equal({'id' => 'BarID', 'description' => 'baz'}, node['a'].deref.node_content)
93
- end
94
- end
95
- end
96
- describe '#[]' do
97
- describe 'without dereferencing' do
98
- let(:node_document) { [0, {'x' => [{'a' => ['b']}]}] }
99
- it 'subscripts arrays and hashes' do
100
- assert_equal('b', node[1]['x'][0]['a'][0])
101
- end
102
- it 'returns ArrayNode for an array' do
103
- subscripted = node[1]['x']
104
- assert_instance_of(JSI::JSON::ArrayNode, subscripted)
105
- assert_equal([{'a' => ['b']}], subscripted.node_content)
106
- assert_equal(JSI::JSON::Pointer.new([1, 'x']), subscripted.node_ptr)
107
- end
108
- it 'returns HashNode for a Hash' do
109
- subscripted = node[1]
110
- assert_instance_of(JSI::JSON::HashNode, subscripted)
111
- assert_equal({'x' => [{'a' => ['b']}]}, subscripted.node_content)
112
- assert_equal(JSI::JSON::Pointer.new([1]), subscripted.node_ptr)
113
- end
114
- describe 'node_content does not respond to []' do
115
- let(:node_document) { Object.new }
116
- it 'cannot subscript' do
117
- err = assert_raises(NoMethodError) { node['x'] }
118
- assert_equal("undefined method `[]`\nsubscripting with \"x\" (String) from Object. content is: #{node_document.pretty_inspect.chomp}", err.message)
119
- end
120
- end
121
- end
122
- describe 'with dereferencing' do
123
- let(:node_document) do
124
- {
125
- 'foo' => {'bar' => ['baz']},
126
- 'a' => {'$ref' => '#/foo', 'description' => 'hi'}, # not sure a description is actually allowed here, whatever
127
- }
128
- end
129
- it 'subscripts a node consisting of a $ref without following' do
130
- subscripted = node['a']
131
- assert_equal({'$ref' => '#/foo', 'description' => 'hi'}, subscripted.node_content)
132
- assert_equal(JSI::JSON::Pointer.new(['a']), subscripted.node_ptr)
133
- end
134
- end
135
- end
136
- describe '#[]=' do
137
- let(:node_document) { [0, {'x' => [{'a' => ['b']}]}] }
138
- it 'assigns' do
139
- node[0] = 'abcdefg'
140
- assert_equal(['abcdefg', {'x' => [{'a' => ['b']}]}], node_document)
141
- string_node = JSI::JSON::Node.new(node_document, JSI::JSON::Pointer.new([0]))
142
- string_node[0..2] = '0'
143
- assert_equal(['0defg', {'x' => [{'a' => ['b']}]}], node_document)
144
- node[0] = node[1]
145
- assert_equal([{'x' => [{'a' => ['b']}]}, {'x' => [{'a' => ['b']}]}], node_document)
146
- end
147
- it 'assigns, deeper' do
148
- node[1]['y'] = node[1]['x'][0]
149
- assert_equal([0, {'x' => [{'a' => ['b']}], 'y' => {'a' => ['b']}}], node_document)
150
- end
151
- end
152
- describe '#document_root_node' do
153
- let(:node_document) { {'a' => {'b' => 3}} }
154
- it 'has node_content that is the node_document' do
155
- assert_equal({'a' => {'b' => 3}}, node['a'].document_root_node.node_content)
156
- end
157
- end
158
- describe '#parent_node' do
159
- let(:node_document) { {'a' => {'b' => []}} }
160
- it 'finds a parent' do
161
- sub = node['a']['b']
162
- assert_equal(JSI::JSON::Pointer.new(['a', 'b']), sub.node_ptr)
163
- parent = sub.parent_node
164
- assert_equal(JSI::JSON::Pointer.new(['a']), parent.node_ptr)
165
- assert_equal({'b' => []}, parent.node_content)
166
- assert_equal(node['a'], parent)
167
- root_from_sub = sub.parent_node.parent_node
168
- assert_equal(JSI::JSON::Pointer.new([]), root_from_sub.node_ptr)
169
- assert_equal({'a' => {'b' => []}}, root_from_sub.node_content)
170
- assert_equal(node, root_from_sub)
171
- err = assert_raises(JSI::JSON::Pointer::ReferenceError) do
172
- root_from_sub.parent_node
173
- end
174
- assert_equal('cannot access parent of root pointer: JSI::JSON::Pointer[]', err.message)
175
- end
176
- end
177
- describe '#modified_copy' do
178
- let(:node_document) { [['b', 'q'], {'c' => ['d', 'e']}] }
179
- let(:path) { ['1', 'c'] }
180
- it 'returns a different object' do
181
- # simplest thing
182
- modified_dup = node.modified_copy(&:dup)
183
- # it is equal - being a dup
184
- assert_equal(node, modified_dup)
185
- # but different object
186
- refute_equal(node.object_id, modified_dup.object_id)
187
- # the parents, obviously, are different
188
- refute_equal(node.parent_node.node_content.object_id, modified_dup.parent_node.node_content.object_id)
189
- refute_equal(node.parent_node.parent_node.node_content.object_id, modified_dup.parent_node.parent_node.node_content.object_id)
190
- # but any untouched part(s) - in this case the ['b', 'q'] at node_document[0] - are untouched
191
- assert_equal(node.document_root_node[0].node_content.object_id, modified_dup.document_root_node[0].node_content.object_id)
192
- end
193
- it 'returns the same object' do
194
- unmodified_dup = node.modified_copy { |o| o }
195
- assert_equal(unmodified_dup, node)
196
- # same object, since the block just returned it
197
- refute_equal(node.object_id, unmodified_dup.object_id)
198
- # the parents are unchanged since the object is the same
199
- assert_equal(node.parent_node.node_content.object_id, unmodified_dup.parent_node.node_content.object_id)
200
- assert_equal(node.parent_node.parent_node.node_content.object_id, unmodified_dup.parent_node.parent_node.node_content.object_id)
201
- # same as the other: any untouched part(s) - in this case the ['b', 'q'] at node_document[0] - are untouched
202
- assert_equal(node.document_root_node[0].node_content.object_id, unmodified_dup.document_root_node[0].node_content.object_id)
203
- end
204
- it 'raises subscripting string from array' do
205
- err = assert_raises(TypeError) { JSI::JSON::Node.new(node_document, JSI::JSON::Pointer.new(['x'])).modified_copy(&:dup) }
206
- assert_match(%r(\Abad subscript "x" with remaining subpath: \[\] for array: \[.*\]\z)m, err.message)
207
- end
208
- it 'raises subscripting from invalid subpath' do
209
- err = assert_raises(TypeError) { JSI::JSON::Node.new(node_document, JSI::JSON::Pointer.new([0, 0, 'what'])).modified_copy(&:dup) }
210
- assert_match(%r(bad subscript: "what" with remaining subpath: \[\] for content: "b"\z)m, err.message)
211
- end
212
- end
213
- describe '#inspect' do
214
- let(:node_document) { {'a' => {'c' => ['d', 'e']}} }
215
- let(:path) { ['a'] }
216
- it 'inspects' do
217
- assert_equal(%Q(#<JSI::JSON::Node #/a {"c"=>["d", "e"]}>), node.inspect)
218
- end
219
- end
220
- describe '#pretty_print' do
221
- let(:node_document) { {'a' => {'c' => ['d', 'e']}} }
222
- let(:path) { ['a'] }
223
- it 'pretty prints' do
224
- assert_equal(%Q(#<JSI::JSON::Node #/a {"c"=>["d", "e"]}>), node.pretty_inspect.chomp)
225
- end
226
- end
227
- describe '#jsi_fingerprint' do
228
- let(:node_ptr) { JSI::JSON::Pointer.new([]) }
229
- it 'hashes consistently' do
230
- assert_equal('x', {JSI::JSON::Node.new([0], node_ptr) => 'x'}[JSI::JSON::Node.new([0], node_ptr)])
231
- end
232
- it 'hashes consistently regardless of the Node being decorated as a subclass' do
233
- assert_equal('x', {JSI::JSON::Node.new_doc([0]) => 'x'}[JSI::JSON::Node.new([0], node_ptr)])
234
- assert_equal('x', {JSI::JSON::Node.new([0], node_ptr) => 'x'}[JSI::JSON::Node.new_doc([0])])
235
- end
236
- it '==' do
237
- assert_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new([0], node_ptr))
238
- assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new([0], node_ptr))
239
- assert_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new_doc([0]))
240
- assert_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc([0]))
241
- end
242
- it '!=' do
243
- refute_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new({}, node_ptr))
244
- refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new({}, node_ptr))
245
- refute_equal(JSI::JSON::Node.new([0], node_ptr), JSI::JSON::Node.new_doc({}))
246
- refute_equal(JSI::JSON::Node.new_doc([0]), JSI::JSON::Node.new_doc({}))
247
- refute_equal({}, JSI::JSON::Node.new_doc({}))
248
- refute_equal(JSI::JSON::Node.new_doc({}), {})
249
- end
250
- end
251
- describe '#as_json' do
252
- let(:node_document) { {'a' => 'b'} }
253
- it '#as_json' do
254
- assert_equal({'a' => 'b'}, node.as_json)
255
- end
256
- end
257
- end
@@ -1,102 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe JSI::JSON::Pointer do
4
- # For example, given the document
5
- let(:document) do
6
- {
7
- "foo" => ["bar", "baz"],
8
- "" => 0,
9
- "a/b" => 1,
10
- "c%d" => 2,
11
- "e^f" => 3,
12
- "g|h" => 4,
13
- "i\\j" => 5,
14
- "k\"l" => 6,
15
- " " => 7,
16
- "m~n" => 8,
17
- }
18
- end
19
-
20
- describe 'initialize from pointer' do
21
- it 'parses' do
22
- # The following strings evaluate to the accompanying values:
23
- evaluations = [
24
- "" , document,
25
- "/foo" , ["bar", "baz"],
26
- "/foo/0", "bar",
27
- "/" , 0,
28
- "/a~1b" , 1,
29
- "/c%d" , 2,
30
- "/e^f" , 3,
31
- "/g|h" , 4,
32
- "/i\\j" , 5,
33
- "/k\"l" , 6,
34
- "/ " , 7,
35
- "/m~0n" , 8,
36
- ]
37
- evaluations.each_slice(2) do |pointer, value|
38
- assert_equal(value, JSI::JSON::Pointer.from_pointer(pointer).evaluate(document))
39
- end
40
- end
41
-
42
- it 'raises for invalid syntax' do
43
- err = assert_raises(JSI::JSON::Pointer::PointerSyntaxError) do
44
- JSI::JSON::Pointer.from_pointer("this does not begin with slash").evaluate(document)
45
- end
46
- assert_equal("Invalid pointer syntax in \"this does not begin with slash\": pointer must begin with /", err.message)
47
- end
48
- end
49
- describe 'initialize from fragment' do
50
- # For example, given the document
51
- let(:document) do
52
- {
53
- "foo" => ["bar", "baz"],
54
- "" => 0,
55
- "a/b" => 1,
56
- "c%d" => 2,
57
- "e^f" => 3,
58
- "g|h" => 4,
59
- "i\\j" => 5,
60
- "k\"l" => 6,
61
- " " => 7,
62
- "m~n" => 8,
63
- }
64
- end
65
-
66
- it 'parses' do
67
- # the following URI fragment identifiers evaluate to the accompanying values:
68
- evaluations = [
69
- '#', document,
70
- '#/foo', ["bar", "baz"],
71
- '#/foo/0', "bar",
72
- '#/', 0,
73
- '#/a~1b', 1,
74
- '#/c%25d', 2,
75
- '#/e%5Ef', 3,
76
- '#/g%7Ch', 4,
77
- '#/i%5Cj', 5,
78
- '#/k%22l', 6,
79
- '#/%20', 7,
80
- '#/m~0n', 8,
81
- ]
82
- evaluations.each_slice(2) do |uri, value|
83
- assert_equal(value, JSI::JSON::Pointer.from_fragment(Addressable::URI.parse(uri).fragment).evaluate(document))
84
- end
85
- end
86
-
87
- it 'raises for invalid syntax' do
88
- err = assert_raises(JSI::JSON::Pointer::PointerSyntaxError) do
89
- JSI::JSON::Pointer.from_fragment("this does not begin with slash").evaluate(document)
90
- end
91
- assert_equal("Invalid pointer syntax in \"this does not begin with slash\": pointer must begin with /", err.message)
92
- end
93
- end
94
- describe 'initialize' do
95
- describe 'invalid reference_tokens' do
96
- it 'raises' do
97
- err = assert_raises(TypeError) { JSI::JSON::Pointer.new({}) }
98
- assert_equal("reference_tokens must be an array. got: {}", err.message)
99
- end
100
- end
101
- end
102
- end
data/test/jsi_test.rb DELETED
@@ -1,11 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- class JSITest < Minitest::Test
4
- def test_that_it_has_a_version_number
5
- refute_nil ::JSI::VERSION
6
- end
7
-
8
- def test_it_does_something_useful
9
- assert true
10
- end
11
- end