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
data/test/base_test.rb DELETED
@@ -1,486 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- NamedSchemaInstance = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/base/named_schema'}).jsi_schema_class
4
-
5
- # hitting .tap(&:name) causes JSI to assign a constant name from the ID,
6
- # meaning the name NamedSchemaInstanceTwo is not known.
7
- NamedSchemaInstanceTwo = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/base/named_schema_two'}).jsi_schema_class.tap(&:name)
8
-
9
- describe JSI::Base do
10
- let(:schema_content) { {} }
11
- let(:schema) { JSI::Schema.new(schema_content) }
12
- let(:instance) { {} }
13
- let(:subject) { schema.new_jsi(instance) }
14
- describe 'class .inspect' do
15
- it 'is the same as Class#inspect on the base' do
16
- assert_equal('JSI::Base', JSI::Base.inspect)
17
- end
18
- it 'is (JSI Schema Class) for generated subclass without id' do
19
- assert_equal("(JSI Schema Class: #)", subject.class.inspect)
20
- end
21
- describe 'with schema id' do
22
- let(:schema_content) { {'id' => 'https://jsi/foo'} }
23
- it 'is (JSI Schema Class: ...) for generated subclass with id' do
24
- assert_equal("(JSI Schema Class: https://jsi/foo#)", subject.class.inspect)
25
- end
26
- end
27
- it 'is the constant name plus id for a class assigned to a constant' do
28
- assert_equal(%q(NamedSchemaInstance (https://schemas.jsi.unth.net/test/base/named_schema#)), NamedSchemaInstance.inspect)
29
- end
30
- it 'is not the constant name when the constant name has been generated from the schema_id' do
31
- assert_equal("JSI::SchemaClasses::Xhttps___schemas_jsi_unth_net_test_base_named_schema_two_", NamedSchemaInstanceTwo.name)
32
- assert_equal("(JSI Schema Class: https://schemas.jsi.unth.net/test/base/named_schema_two#)", NamedSchemaInstanceTwo.inspect)
33
- end
34
- end
35
- describe 'class name' do
36
- let(:schema_content) { {'id' => 'https://jsi/BaseTest'} }
37
- it 'generates a class name from schema_id' do
38
- assert_equal('JSI::SchemaClasses::Xhttps___jsi_BaseTest_', subject.class.name)
39
- end
40
- it 'uses an existing name' do
41
- assert_equal('NamedSchemaInstance', NamedSchemaInstance.name)
42
- end
43
- end
44
- describe 'class for schema .jsi_class_schemas' do
45
- it '.jsi_class_schemas' do
46
- assert_equal(Set.new << schema, schema.jsi_schema_class.jsi_class_schemas)
47
- end
48
- end
49
- describe 'module for schema .inspect' do
50
- it '.inspect' do
51
- assert_equal("(JSI Schema Module: #)", JSI::SchemaClasses.module_for_schema(schema).inspect)
52
- end
53
- end
54
- describe 'module for schema .schema' do
55
- it '.schema' do
56
- assert_equal(schema, JSI::SchemaClasses.module_for_schema(schema).schema)
57
- end
58
- end
59
- describe '.class_for_schemas' do
60
- it 'returns a class from a schema' do
61
- class_for_schema = JSI.class_for_schemas([schema])
62
- # same class every time
63
- assert_equal(JSI.class_for_schemas([schema]), class_for_schema)
64
- assert_operator(class_for_schema, :<, JSI::Base)
65
- end
66
- it 'returns the same class from a hash' do
67
- assert_equal(JSI.class_for_schemas([schema]), JSI.class_for_schemas([schema_content]))
68
- end
69
- end
70
- describe 'JSI::SchemaClasses.module_for_schema' do
71
- it 'returns a module from a schema' do
72
- module_for_schema = JSI::SchemaClasses.module_for_schema(schema)
73
- # same module every time
74
- assert_equal(JSI::SchemaClasses.module_for_schema(schema), module_for_schema)
75
- end
76
- it 'returns a module from a hash' do
77
- assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema.jsi_instance))
78
- end
79
- end
80
- describe 'initialization' do
81
- describe 'on Base' do
82
- it 'errors' do
83
- err = assert_raises(TypeError) { JSI::Base.new({}) }
84
- assert_equal('cannot instantiate JSI::Base which has no method #jsi_schemas. it is recommended to instantiate JSIs from a schema using JSI::Schema#new_jsi.', err.message)
85
- end
86
- end
87
- describe 'nil' do
88
- let(:instance) { nil }
89
- it 'initializes with nil instance' do
90
- assert_equal(nil, subject.jsi_instance)
91
- assert(!subject.respond_to?(:to_ary))
92
- assert(!subject.respond_to?(:to_hash))
93
- end
94
- end
95
- describe 'arbitrary instance' do
96
- let(:instance) { Object.new }
97
- it 'initializes' do
98
- assert_equal(instance, subject.jsi_instance)
99
- assert(!subject.respond_to?(:to_ary))
100
- assert(!subject.respond_to?(:to_hash))
101
- end
102
- end
103
- describe 'hash' do
104
- let(:instance) { {'foo' => 'bar'} }
105
- let(:schema_content) { {'type' => 'object'} }
106
- it 'initializes' do
107
- assert_equal({'foo' => 'bar'}, subject.jsi_instance)
108
- assert(!subject.respond_to?(:to_ary))
109
- assert(subject.respond_to?(:to_hash))
110
- end
111
- end
112
- describe 'JSI::JSON::HashNode' do
113
- let(:instance) { JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])) }
114
- let(:schema_content) { {'type' => 'object'} }
115
- it 'initializes' do
116
- assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])), subject.jsi_instance)
117
- assert(!subject.respond_to?(:to_ary))
118
- assert(subject.respond_to?(:to_hash))
119
- end
120
- end
121
- describe 'array' do
122
- let(:instance) { ['foo'] }
123
- let(:schema_content) { {'type' => 'array'} }
124
- it 'initializes' do
125
- assert_equal(['foo'], subject.jsi_instance)
126
- assert(subject.respond_to?(:to_ary))
127
- assert(!subject.respond_to?(:to_hash))
128
- end
129
- end
130
- describe 'JSI::JSON::ArrayNode' do
131
- let(:instance) { JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])) }
132
- let(:schema_content) { {'type' => 'array'} }
133
- it 'initializes' do
134
- assert_equal(JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])), subject.jsi_instance)
135
- assert(subject.respond_to?(:to_ary))
136
- assert(!subject.respond_to?(:to_hash))
137
- end
138
- end
139
- describe 'another JSI::Base invalid' do
140
- let(:schema_content) { {'type' => 'object'} }
141
- let(:instance) { schema.new_jsi({'foo' => 'bar'}) }
142
- it 'initializes with an error' do
143
- err = assert_raises(TypeError) { subject }
144
- assert_equal("assigning another JSI::Base instance to a (JSI Schema Class: #) instance is incorrect. received: \#{<JSI> \"foo\" => \"bar\"}", err.message)
145
- end
146
- end
147
- describe 'Schema invalid' do
148
- let(:instance) { JSI::Schema.new({}) }
149
- it 'initializes with an error' do
150
- err = assert_raises(TypeError) { subject }
151
- assert_equal("assigning a schema to a (JSI Schema Class: #) instance is incorrect. received: \#{<JSI (JSI::JSONSchemaOrgDraft06) Schema>}", err.message)
152
- end
153
- end
154
- end
155
- describe '#parent_jsis, #parent_jsi' do
156
- let(:schema_content) { {'properties' => {'foo' => {'properties' => {'bar' => {'properties' => {'baz' => {}}}}}}} }
157
- let(:instance) { {'foo' => {'bar' => {'baz' => {}}}} }
158
- describe 'no parent_jsis' do
159
- it 'has none' do
160
- assert_equal([], subject.parents)
161
- assert_equal([], subject.parent_jsis)
162
- assert_equal(nil, subject.parent)
163
- assert_equal(nil, subject.parent_jsi)
164
- end
165
- end
166
- describe 'one parent_jsi' do
167
- it 'has one' do
168
- assert_equal([subject], subject.foo.parents)
169
- assert_equal([subject], subject.foo.parent_jsis)
170
- assert_equal(subject, subject.foo.parent)
171
- assert_equal(subject, subject.foo.parent_jsi)
172
- end
173
- end
174
- describe 'more parent_jsis' do
175
- it 'has more' do
176
- assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parents)
177
- assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parent_jsis)
178
- assert_equal(subject.foo.bar, subject.foo.bar.baz.parent)
179
- assert_equal(subject.foo.bar, subject.foo.bar.baz.parent_jsi)
180
- end
181
- end
182
- end
183
- describe '#each, Enumerable methods' do
184
- let(:instance) { 'a string' }
185
- it "raises NoMethodError calling each or Enumerable methods" do
186
- assert_raises(NoMethodError) { subject.each { nil } }
187
- assert_raises(NoMethodError) { subject.map { nil } }
188
- end
189
- end
190
- describe '#modified_copy' do
191
- describe 'with an instance that does not have #modified_copy' do
192
- let(:instance) { Object.new }
193
- it 'yields the instance to modify' do
194
- new_instance = Object.new
195
- modified = subject.modified_copy do |o|
196
- assert_equal(instance, o)
197
- new_instance
198
- end
199
- assert_equal(new_instance, modified.jsi_instance)
200
- assert_equal(instance, subject.jsi_instance)
201
- refute_equal(instance, modified)
202
- end
203
- end
204
- describe 'with an instance that does have #modified_copy' do
205
- it 'yields the instance to modify' do
206
- modified = subject.modified_copy do |o|
207
- assert_equal({}, o)
208
- {'a' => 'b'}
209
- end
210
- assert_equal({'a' => 'b'}, modified.jsi_instance)
211
- assert_equal({}, subject.jsi_instance)
212
- refute_equal(instance, modified)
213
- end
214
- end
215
- describe 'no modification' do
216
- it 'yields the instance to modify' do
217
- modified = subject.modified_copy { |o| o }
218
- # this doesn't really need to be tested but ... whatever
219
- assert_equal(subject.jsi_instance.object_id, modified.jsi_instance.object_id)
220
- assert_equal(subject, modified)
221
- refute_equal(subject.object_id, modified.object_id)
222
- end
223
- end
224
- describe 'resulting in a different type' do
225
- let(:schema_content) { {'type' => 'object'} }
226
- it 'works' do
227
- # I'm not really sure the best thing to do here, but this is how it is for now. this is subject to change.
228
- modified = subject.modified_copy do |o|
229
- o.to_s
230
- end
231
- assert_equal('{}', modified.jsi_instance)
232
- assert_equal({}, subject.jsi_instance)
233
- refute_equal(instance, modified)
234
- # interesting side effect
235
- assert(subject.respond_to?(:to_hash))
236
- assert(!modified.respond_to?(:to_hash))
237
- end
238
- end
239
- end
240
- describe 'validation' do
241
- describe 'without errors' do
242
- it '#fully_validate' do
243
- assert_equal([], subject.fully_validate)
244
- end
245
- it '#validate' do
246
- assert_equal(true, subject.validate)
247
- end
248
- it '#validate!' do
249
- assert_equal(true, subject.validate!)
250
- end
251
- end
252
- describe 'with errors' do
253
- let(:schema_content) {
254
- {
255
- 'id' => 'https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors',
256
- 'type' => 'object',
257
- 'properties' => {
258
- 'some_number' => {
259
- 'type' => 'number'
260
- },
261
- 'a_required_property' => {
262
- 'type' => 'string'
263
- }
264
- }
265
- }
266
- }
267
- let(:instance) { "this is a string" }
268
-
269
- it '#validate' do
270
- assert_equal(false, subject.validate)
271
- end
272
- it '#validate!' do
273
- assert_raises JSON::Schema::ValidationError do
274
- subject.validate!
275
- end
276
- end
277
- describe 'fully_validate' do
278
- it '#fully_validate ' do
279
- assert_equal(["The property '#/' of type string did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors"], subject.fully_validate)
280
- end
281
- it '#fully_validate :errors_as_objects' do
282
- expected = [
283
- {
284
- :schema => Addressable::URI.parse('https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors'),
285
- :fragment => "#/",
286
- :message => "The property '#/' of type string did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors",
287
- :failed_attribute=>"TypeV4"
288
- }
289
- ]
290
- assert_equal(expected, subject.fully_validate(:errors_as_objects => true))
291
- end
292
- end
293
- end
294
- describe 'at a depth' do
295
- let(:schema_content) do
296
- {
297
- 'id' => 'https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth',
298
- 'description' => 'hash schema',
299
- 'type' => 'object',
300
- 'properties' => {
301
- 'foo' => {'type' => 'object'},
302
- 'bar' => {},
303
- 'baz' => {'type' => 'array'},
304
- },
305
- 'additionalProperties' => {'not' => {}},
306
- }
307
- end
308
-
309
- describe 'without errors' do
310
- let(:instance) { {'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => [true]} }
311
-
312
- it '#fully_validate' do
313
- assert_equal([], subject.foo.fully_validate)
314
- assert_equal([], subject.bar.fully_validate)
315
- end
316
- it '#validate' do
317
- assert_equal(true, subject.foo.validate)
318
- assert_equal(true, subject.bar.validate)
319
- end
320
- end
321
- describe 'with errors' do
322
- let(:instance) { {'foo' => [true], 'bar' => [9], 'baz' => {'x' => 'y'}, 'more' => {}} }
323
-
324
- it '#fully_validate' do
325
- assert_equal(["The property '#/' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.foo.fully_validate)
326
- assert_equal([], subject.bar.fully_validate)
327
- assert_equal(["The property '#/' of type object did not match the following type: array in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.baz.fully_validate)
328
- assert_equal(["The property '#/' of type object matched the disallowed schema in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject['more'].fully_validate)
329
- assert_equal(["The property '#/foo' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth", "The property '#/baz' of type object did not match the following type: array in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth", "The property '#/more' of type object matched the disallowed schema in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.fully_validate)
330
- end
331
- it '#validate' do
332
- assert_equal(false, subject.foo.validate)
333
- assert_equal(true, subject.bar.validate)
334
- assert_equal(false, subject.baz.validate)
335
- assert_equal(false, subject['more'].validate)
336
- assert_equal(false, subject.validate)
337
- end
338
- end
339
- end
340
- end
341
- describe 'property accessors' do
342
- let(:schema_content) do
343
- {
344
- 'type' => 'object',
345
- 'properties' => {
346
- 'foo' => {'type' => 'object'},
347
- 'bar' => {'type' => 'array'},
348
- 'baz' => {},
349
- },
350
- }
351
- end
352
- let(:instance) do
353
- {'foo' => {'x' => 'y'}, 'bar' => [3.14159], 'baz' => true, 'qux' => []}
354
- end
355
- describe 'readers' do
356
- it 'reads attributes described as properties' do
357
- assert_equal({'x' => 'y'}, subject.foo.as_json)
358
- assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
359
- assert_respond_to(subject.foo, :to_hash)
360
- refute_respond_to(subject.foo, :to_ary)
361
- assert_equal([3.14159], subject.bar.as_json)
362
- assert_is_a(schema.properties['bar'].jsi_schema_module, subject.bar)
363
- refute_respond_to(subject.bar, :to_hash)
364
- assert_respond_to(subject.bar, :to_ary)
365
- assert_equal(true, subject.baz)
366
- refute_respond_to(subject.baz, :to_hash)
367
- refute_respond_to(subject.baz, :to_ary)
368
- refute_respond_to(subject, :qux)
369
- end
370
- describe 'when the instance is not hashlike' do
371
- let(:instance) { nil }
372
- it 'errors' do
373
- err = assert_raises(JSI::Base::CannotSubscriptError) { subject.foo }
374
- assert_equal(%q(cannot subcript (using token: "foo") from instance: nil), err.message)
375
- end
376
- end
377
- describe 'properties with the same names as instance methods' do
378
- let(:schema_content) do
379
- {
380
- 'type' => 'object',
381
- 'properties' => {
382
- 'foo' => {}, # not an instance method
383
- 'initialize' => {}, # Base
384
- 'inspect' => {}, # Base
385
- 'pretty_inspect' => {}, # Kernel
386
- 'as_json' => {}, # Base::OverrideFromExtensions, extended on initialization
387
- 'each' => {}, # PathedHashNode / PathedArrayNode
388
- 'instance_exec' => {}, # BasicObject
389
- 'jsi_instance' => {}, # Base
390
- 'jsi_schemas' => {}, # module_for_schema singleton definition
391
- },
392
- }
393
- end
394
- let(:instance) do
395
- {
396
- 'foo' => 'bar',
397
- 'initialize' => 'hi',
398
- 'inspect' => 'hi',
399
- 'pretty_inspect' => 'hi',
400
- 'as_json' => 'hi',
401
- 'each' => 'hi',
402
- 'instance_exec' => 'hi',
403
- 'jsi_instance' => 'hi',
404
- 'jsi_schemas' => 'hi',
405
- }
406
- end
407
- it 'does not define readers' do
408
- assert_equal('bar', subject.foo) # this one is defined
409
-
410
- assert_equal(JSI::Base, subject.method(:initialize).owner)
411
- assert_equal('hi', subject['initialize'])
412
- assert_equal(%q(#{<JSI> "foo" => "bar", "initialize" => "hi", "inspect" => "hi", "pretty_inspect" => "hi", "as_json" => "hi", "each" => "hi", "instance_exec" => "hi", "jsi_instance" => "hi", "jsi_schemas" => "hi"}), subject.inspect)
413
- assert_equal('hi', subject['inspect'])
414
- assert_equal(%Q(\#{<JSI>\n "foo" => "bar",\n "initialize" => "hi",\n "inspect" => "hi",\n "pretty_inspect" => "hi",\n "as_json" => "hi",\n "each" => "hi",\n "instance_exec" => "hi",\n "jsi_instance" => "hi",\n "jsi_schemas" => "hi"\n}\n), subject.pretty_inspect)
415
- assert_equal(instance, subject.as_json)
416
- assert_equal(subject, subject.each { })
417
- assert_equal(2, subject.instance_exec { 2 })
418
- assert_equal(instance, subject.jsi_instance)
419
- assert_equal(Set.new << schema, subject.jsi_schemas)
420
- end
421
- end
422
- end
423
- describe 'writers' do
424
- it 'writes attributes described as properties' do
425
- orig_foo = subject.foo
426
-
427
- subject.foo = {'y' => 'z'}
428
-
429
- assert_equal({'y' => 'z'}, subject.foo.as_json)
430
- assert_is_a(schema.properties['foo'].jsi_schema_module, orig_foo)
431
- assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
432
- end
433
- it 'modifies the instance, visible to other references to the same instance' do
434
- orig_instance = subject.jsi_instance
435
-
436
- subject.foo = {'y' => 'z'}
437
-
438
- assert_equal(orig_instance, subject.jsi_instance)
439
- assert_equal({'y' => 'z'}, orig_instance['foo'])
440
- assert_equal({'y' => 'z'}, subject.jsi_instance['foo'])
441
- assert_equal(orig_instance.class, subject.jsi_instance.class)
442
- end
443
- describe 'when the instance is not hashlike' do
444
- let(:instance) { nil }
445
- it 'errors' do
446
- err = assert_raises(NoMethodError) { subject.foo = 0 }
447
- assert_equal('cannot assign subcript (using token: "foo") to instance: nil', err.message)
448
- end
449
- end
450
- end
451
- end
452
- describe '#inspect' do
453
- # if the instance is hash-like, #inspect gets overridden
454
- let(:instance) { Object.new }
455
- it 'inspects' do
456
- assert_match(%r(\A\#<JSI\ \#<Object:[^<>]*>>\z), subject.inspect)
457
- end
458
- end
459
- describe '#pretty_print' do
460
- # if the instance is hash-like, #pretty_print gets overridden
461
- let(:instance) { Object.new }
462
- it 'pretty_prints' do
463
- assert_match(%r(\A\#<JSI\ \#<Object:[^<>]*>>\z), subject.pretty_inspect.chomp)
464
- end
465
- end
466
- describe '#as_json' do
467
- it '#as_json' do
468
- assert_equal({'a' => 'b'}, JSI::Schema.new({}).new_jsi({'a' => 'b'}).as_json)
469
- assert_equal({'a' => 'b'}, JSI::Schema.new({}).new_jsi(JSI::JSON::Node.new_doc({'a' => 'b'})).as_json)
470
- assert_equal({'a' => 'b'}, JSI::Schema.new({'type' => 'object'}).new_jsi(JSI::JSON::Node.new_doc({'a' => 'b'})).as_json)
471
- assert_equal(['a', 'b'], JSI::Schema.new({'type' => 'array'}).new_jsi(JSI::JSON::Node.new_doc(['a', 'b'])).as_json)
472
- assert_equal(['a'], JSI::Schema.new({}).new_jsi(['a']).as_json(some_option: true))
473
- end
474
- end
475
- describe 'equality between different classes of JSI::Base subclasses' do
476
- let(:subject_subclass) { Class.new(schema.jsi_schema_class).new(instance) }
477
-
478
- it 'considers a Base subclass (class_for_schema) and subsubclass to be equal with the same instance' do
479
- assert_equal(subject.hash, subject_subclass.hash)
480
- assert(subject == subject_subclass)
481
- assert(subject_subclass == subject)
482
- assert(subject.eql?(subject_subclass))
483
- assert(subject_subclass.eql?(subject))
484
- end
485
- end
486
- end
@@ -1,85 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe JSI::JSICoder do
4
- let(:schema_content) do
5
- {properties: {foo: {}, bar: {}}}
6
- end
7
- let(:schema) { JSI::Schema.new(schema_content) }
8
- let(:options) { {} }
9
- let(:schema_instance_json_coder) { JSI::JSICoder.new(schema, options) }
10
- describe 'json' do
11
- describe 'load' do
12
- it 'loads nil' do
13
- assert_nil(schema_instance_json_coder.load(nil))
14
- end
15
- it 'loads a hash' do
16
- assert_equal(schema.new_jsi('foo' => 'bar'), schema_instance_json_coder.load({"foo" => "bar"}))
17
- end
18
- it 'loads something else' do
19
- assert_equal(schema.new_jsi([[]]), schema_instance_json_coder.load([[]]))
20
- end
21
- describe 'array' do
22
- let(:options) { {array: true} }
23
- it 'loads an array of hashes' do
24
- data = [{"foo" => "bar"}, {"foo" => "baz"}]
25
- assert_equal([schema.new_jsi('foo' => 'bar'), schema.new_jsi('foo' => 'baz')], schema_instance_json_coder.load(data))
26
- end
27
- it 'loads an empty array' do
28
- assert_equal([], schema_instance_json_coder.load([]))
29
- end
30
- it 'loads a not an array' do
31
- assert_raises(TypeError) do
32
- schema_instance_json_coder.load(Object.new)
33
- end
34
- end
35
- end
36
- describe 'array schema' do
37
- let(:schema_content) { {items: {properties: {foo: {}, bar: {}}}} }
38
- it 'loads an array of hashes' do
39
- data = [{"foo" => "bar"}, {"foo" => "baz"}]
40
- assert_equal(schema.new_jsi([{'foo' => 'bar'}, {'foo' => 'baz'}]), schema_instance_json_coder.load(data))
41
- end
42
- it 'loads an empty array' do
43
- assert_equal(schema.new_jsi([]), schema_instance_json_coder.load([]))
44
- end
45
- it 'loads a not an array' do
46
- instance = Object.new
47
- assert_equal(schema.new_jsi(instance), schema_instance_json_coder.load(instance))
48
- end
49
- end
50
- end
51
- describe 'dump' do
52
- it 'dumps nil' do
53
- assert_nil(schema_instance_json_coder.dump(nil))
54
- end
55
- it 'dumps a schema_instance_class' do
56
- assert_equal({"foo" => "x", "bar" => "y"}, schema_instance_json_coder.dump(schema.new_jsi(foo: 'x', bar: 'y')))
57
- end
58
- it 'dumps something else' do
59
- assert_raises(TypeError) do
60
- schema_instance_json_coder.dump(Object.new)
61
- end
62
- end
63
- it 'dumps some of the keys of a schema_instance_class after loading in a partial one' do
64
- schema_instance_class = schema_instance_json_coder.load({'foo' => 'who'})
65
- assert_equal({'foo' => 'who'}, schema_instance_json_coder.dump(schema_instance_class))
66
- schema_instance_class.bar = 'whar'
67
- assert_equal({'foo' => 'who', 'bar' => 'whar'}, schema_instance_json_coder.dump(schema_instance_class))
68
- end
69
- describe 'array' do
70
- let(:options) { {array: true} }
71
- it 'dumps an array of schema_instances' do
72
- schema_instances = [schema.new_jsi(foo: 'x', bar: 'y'), schema.new_jsi(foo: 'z', bar: 'q')]
73
- assert_equal([{"foo" => "x", "bar" => "y"}, {"foo" => "z", "bar" => "q"}], schema_instance_json_coder.dump(schema_instances))
74
- end
75
- end
76
- describe 'array schema' do
77
- let(:schema_content) { {items: {properties: {foo: {}, bar: {}}}} }
78
- it 'dumps a schema_instance array' do
79
- schema_instances = schema.new_jsi([{foo: 'x', bar: 'y'}, {foo: 'z', bar: 'q'}])
80
- assert_equal([{"foo" => "x", "bar" => "y"}, {"foo" => "z", "bar" => "q"}], schema_instance_json_coder.dump(schema_instances))
81
- end
82
- end
83
- end
84
- end
85
- end