lutaml-model 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-tests.yml +2 -0
  3. data/.rubocop_todo.yml +86 -23
  4. data/Gemfile +2 -0
  5. data/README.adoc +1441 -220
  6. data/lib/lutaml/model/attribute.rb +33 -10
  7. data/lib/lutaml/model/choice.rb +56 -0
  8. data/lib/lutaml/model/config.rb +1 -0
  9. data/lib/lutaml/model/constants.rb +7 -0
  10. data/lib/lutaml/model/error/choice_lower_bound_error.rb +9 -0
  11. data/lib/lutaml/model/error/choice_upper_bound_error.rb +9 -0
  12. data/lib/lutaml/model/error/import_model_with_root_error.rb +9 -0
  13. data/lib/lutaml/model/error/incorrect_sequence_error.rb +9 -0
  14. data/lib/lutaml/model/error/invalid_choice_range_error.rb +20 -0
  15. data/lib/lutaml/model/error/no_root_mapping_error.rb +9 -0
  16. data/lib/lutaml/model/error/no_root_namespace_error.rb +9 -0
  17. data/lib/lutaml/model/error/type/invalid_value_error.rb +19 -0
  18. data/lib/lutaml/model/error/unknown_sequence_mapping_error.rb +9 -0
  19. data/lib/lutaml/model/error.rb +9 -0
  20. data/lib/lutaml/model/json_adapter/standard_json_adapter.rb +6 -1
  21. data/lib/lutaml/model/key_value_mapping.rb +34 -3
  22. data/lib/lutaml/model/key_value_mapping_rule.rb +4 -2
  23. data/lib/lutaml/model/liquefiable.rb +59 -0
  24. data/lib/lutaml/model/mapping_hash.rb +9 -1
  25. data/lib/lutaml/model/mapping_rule.rb +19 -2
  26. data/lib/lutaml/model/schema/templates/simple_type.rb +247 -0
  27. data/lib/lutaml/model/schema/xml_compiler.rb +762 -0
  28. data/lib/lutaml/model/schema.rb +5 -0
  29. data/lib/lutaml/model/schema_location.rb +7 -0
  30. data/lib/lutaml/model/sequence.rb +71 -0
  31. data/lib/lutaml/model/serialize.rb +139 -33
  32. data/lib/lutaml/model/toml_adapter/toml_rb_adapter.rb +1 -2
  33. data/lib/lutaml/model/type/decimal.rb +0 -4
  34. data/lib/lutaml/model/type/hash.rb +11 -11
  35. data/lib/lutaml/model/type/time.rb +3 -3
  36. data/lib/lutaml/model/utils.rb +19 -15
  37. data/lib/lutaml/model/validation.rb +12 -1
  38. data/lib/lutaml/model/version.rb +1 -1
  39. data/lib/lutaml/model/xml_adapter/builder/oga.rb +10 -7
  40. data/lib/lutaml/model/xml_adapter/builder/ox.rb +20 -13
  41. data/lib/lutaml/model/xml_adapter/element.rb +32 -0
  42. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +13 -9
  43. data/lib/lutaml/model/xml_adapter/oga/element.rb +14 -13
  44. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +86 -19
  45. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +19 -15
  46. data/lib/lutaml/model/xml_adapter/xml_document.rb +82 -25
  47. data/lib/lutaml/model/xml_adapter/xml_element.rb +57 -3
  48. data/lib/lutaml/model/xml_mapping.rb +53 -9
  49. data/lib/lutaml/model/xml_mapping_rule.rb +8 -6
  50. data/lib/lutaml/model.rb +2 -0
  51. data/lutaml-model.gemspec +5 -0
  52. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +75 -0
  53. data/spec/ceramic_spec.rb +39 -0
  54. data/spec/fixtures/ceramic.rb +23 -0
  55. data/spec/fixtures/xml/address_example_260.xsd +9 -0
  56. data/spec/fixtures/xml/invalid_math_document.xml +4 -0
  57. data/spec/fixtures/xml/math_document_schema.xsd +56 -0
  58. data/spec/fixtures/xml/test_schema.xsd +53 -0
  59. data/spec/fixtures/xml/user.xsd +10 -0
  60. data/spec/fixtures/xml/valid_math_document.xml +4 -0
  61. data/spec/lutaml/model/cdata_spec.rb +4 -5
  62. data/spec/lutaml/model/choice_spec.rb +168 -0
  63. data/spec/lutaml/model/collection_spec.rb +1 -1
  64. data/spec/lutaml/model/custom_model_spec.rb +7 -21
  65. data/spec/lutaml/model/custom_serialization_spec.rb +74 -2
  66. data/spec/lutaml/model/defaults_spec.rb +3 -1
  67. data/spec/lutaml/model/delegation_spec.rb +7 -5
  68. data/spec/lutaml/model/enum_spec.rb +35 -0
  69. data/spec/lutaml/model/group_spec.rb +160 -0
  70. data/spec/lutaml/model/inheritance_spec.rb +25 -0
  71. data/spec/lutaml/model/key_value_mapping_spec.rb +27 -0
  72. data/spec/lutaml/model/liquefiable_spec.rb +121 -0
  73. data/spec/lutaml/model/map_all_spec.rb +188 -0
  74. data/spec/lutaml/model/mixed_content_spec.rb +95 -56
  75. data/spec/lutaml/model/multiple_mapping_spec.rb +22 -10
  76. data/spec/lutaml/model/schema/xml_compiler_spec.rb +1624 -0
  77. data/spec/lutaml/model/sequence_spec.rb +216 -0
  78. data/spec/lutaml/model/transformation_spec.rb +230 -0
  79. data/spec/lutaml/model/type_spec.rb +138 -31
  80. data/spec/lutaml/model/utils_spec.rb +32 -0
  81. data/spec/lutaml/model/with_child_mapping_spec.rb +2 -2
  82. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +11 -7
  83. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +52 -0
  84. data/spec/lutaml/model/xml_mapping_rule_spec.rb +51 -0
  85. data/spec/lutaml/model/xml_mapping_spec.rb +250 -112
  86. metadata +77 -2
@@ -0,0 +1,1624 @@
1
+ require "spec_helper"
2
+ require "lutaml/model/schema"
3
+ require "lutaml/xsd"
4
+
5
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler do
6
+ describe ".to_models" do
7
+ context "with valid xml schema, it should generate the models" do
8
+ let(:valid_value_xml_example) do
9
+ <<~VALID_XML_EXAMPLE
10
+ <CT_MathTest>
11
+ <MathTest val="1"/>
12
+ <MathTest1 val="1"/>
13
+ </CT_MathTest>
14
+ VALID_XML_EXAMPLE
15
+ end
16
+
17
+ let(:invalid_value_xml_example) do
18
+ <<~INVALID_XML_EXAMPLE
19
+ <CT_MathTest>
20
+ <MathTest val="0"/>
21
+ <MathTest1 val="-3"/>
22
+ </CT_MathTest>
23
+ INVALID_XML_EXAMPLE
24
+ end
25
+
26
+ Dir.mktmpdir do |dir|
27
+ it "creates the model files, requires them, and tests them with valid and invalid xml" do
28
+ described_class.to_models(File.read("spec/fixtures/xml/test_schema.xsd"), output_dir: dir, create_files: true)
29
+ expect(File).to exist("#{dir}/ct_math_test.rb")
30
+ expect(File).to exist("#{dir}/st_integer255.rb")
31
+ expect(File).to exist("#{dir}/long.rb")
32
+ Dir.each_child(dir) { |child| require_relative File.expand_path("#{dir}/#{child}") }
33
+ expect(defined?(CTMathTest)).to eq("constant")
34
+ expect(CTMathTest.from_xml(valid_value_xml_example).to_xml).to be_equivalent_to(valid_value_xml_example)
35
+ expect { CTMathTest.from_xml(invalid_value_xml_example) }.to raise_error(Lutaml::Model::Type::InvalidValueError)
36
+ end
37
+ end
38
+ end
39
+
40
+ context "when processing examples from classes/files generated by valid xml schema" do
41
+ Dir.mktmpdir do |dir|
42
+ before do
43
+ described_class.to_models(
44
+ File.read("spec/fixtures/xml/math_document_schema.xsd"),
45
+ output_dir: dir,
46
+ create_files: true,
47
+ )
48
+ require_relative "#{dir}/math_document"
49
+ end
50
+
51
+ let(:valid_example) do
52
+ File.read("spec/fixtures/xml/valid_math_document.xml")
53
+ end
54
+ let(:invalid_example) do
55
+ File.read("spec/fixtures/xml/invalid_math_document.xml")
56
+ end
57
+
58
+ it "does not raise error with valid example and creates files" do
59
+ expect(defined?(MathDocument)).to eq("constant")
60
+ parsed = MathDocument.from_xml(valid_example)
61
+ expect(parsed.title).to eql("Example Title")
62
+ expect(parsed.ipv4_address).to eql("192.168.1.1")
63
+ expect(parsed.to_xml).to be_equivalent_to(valid_example)
64
+ end
65
+
66
+ it "raises InvalidValueError" do
67
+ expect(defined?(MathDocument)).to eq("constant")
68
+ expect { MathDocument.from_xml(invalid_example) }.to raise_error(Lutaml::Model::Type::InvalidValueError)
69
+ end
70
+ end
71
+ end
72
+
73
+ context "when processing example from lutaml-model#260" do
74
+ Dir.mktmpdir do |dir|
75
+ before do
76
+ described_class.to_models(
77
+ File.read("spec/fixtures/xml/address_example_260.xsd"),
78
+ output_dir: dir,
79
+ create_files: true,
80
+ )
81
+ require_relative "#{dir}/address"
82
+ end
83
+
84
+ let(:address) do
85
+ <<~ADD
86
+ <Address>
87
+ Oxford Street
88
+ <City>London</City>
89
+ <ZIP>E1 6AN</ZIP>
90
+ </Address>
91
+ ADD
92
+ end
93
+
94
+ it "matches parsed xml with input" do
95
+ expect(defined?(Address)).to eq("constant")
96
+ expect(Address.from_xml(address).to_xml).to be_equivalent_to(address)
97
+ end
98
+ end
99
+ end
100
+
101
+ context "when classes are generated but files are not created" do
102
+ let(:schema_classes_hash) do
103
+ described_class.to_models(
104
+ File.read("spec/fixtures/xml/user.xsd"),
105
+ )
106
+ end
107
+
108
+ let(:expected_classes) do
109
+ [
110
+ "NonNegativeInteger",
111
+ "PositiveInteger",
112
+ "Base64Binary",
113
+ "UnsignedLong",
114
+ "UnsignedInt",
115
+ "HexBinary",
116
+ "Token",
117
+ "Long",
118
+ "User",
119
+ ]
120
+ end
121
+
122
+ it "matches the expected class names of the schema" do
123
+ expect(schema_classes_hash.keys).to eql(expected_classes)
124
+ end
125
+ end
126
+
127
+ context "when classes are generated and loaded but files are not created" do
128
+ before do
129
+ described_class.to_models(
130
+ File.read("spec/fixtures/xml/user.xsd"),
131
+ load_classes: true,
132
+ )
133
+ end
134
+
135
+ let(:expected_classes) do
136
+ %w[
137
+ NonNegativeInteger
138
+ PositiveInteger
139
+ Base64Binary
140
+ UnsignedLong
141
+ UnsignedInt
142
+ HexBinary
143
+ Token
144
+ Long
145
+ User
146
+ ]
147
+ end
148
+
149
+ let(:xml) do
150
+ <<~XML
151
+ <User>
152
+ <id>1112</id>
153
+ <age>29</age>
154
+ <token>u9dId901dp13f</token>
155
+ </User>
156
+ XML
157
+ end
158
+
159
+ it "matches the expected class names of the schema" do
160
+ expected_classes.each do |klass|
161
+ expect(be_const_defined(klass)).to be_truthy
162
+ end
163
+ expect(User.from_xml(xml).to_xml).to be_equivalent_to(xml)
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "structure setup methods" do
169
+ describe ".as_models" do
170
+ context "when the XML adapter is not set" do
171
+ before do
172
+ Lutaml::Model::Config.xml_adapter_type = :ox
173
+ end
174
+
175
+ after do
176
+ Lutaml::Model::Config.xml_adapter_type = :nokogiri
177
+ end
178
+
179
+ it "raises an error" do
180
+ expect { described_class.send(:as_models, '<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>') }.to raise_error(Lutaml::Model::Error)
181
+ end
182
+ end
183
+
184
+ context "when the XML adapter is set and schema is given" do
185
+ let(:schema) { '<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>' }
186
+
187
+ it "initializes the instance variables with empty MappingHash" do
188
+ described_class.send(:as_models, schema)
189
+ variables = %i[@elements @attributes @group_types @simple_types @complex_types @attribute_groups]
190
+ variables.each do |variable|
191
+ instance_variable = described_class.instance_variable_get(variable)
192
+ expect(instance_variable).to be_a(Lutaml::Model::MappingHash)
193
+ expect(instance_variable).to be_empty
194
+ end
195
+ end
196
+
197
+ it "parses the schema and populates the instance variables" do
198
+ expect(described_class.send(:as_models, schema)).to be_nil
199
+ end
200
+ end
201
+ end
202
+
203
+ describe ".schema_to_models" do
204
+ context "when given schema element is empty" do
205
+ let(:schema) { [] }
206
+
207
+ it "returns nil if schema array is empty" do
208
+ expect(described_class.send(:schema_to_models, schema)).to be_nil
209
+ end
210
+
211
+ it "returns nil if schema array contains empty schema instance" do
212
+ schema << Lutaml::Xsd::Schema.new
213
+ expect(described_class.send(:schema_to_models, schema)).to be_nil
214
+ end
215
+ end
216
+
217
+ context "when given schema contains all the elements" do
218
+ before do
219
+ variables.each_key do |key|
220
+ described_class.instance_variable_set(:"@#{key}", to_mapping_hash({}))
221
+ end
222
+ end
223
+
224
+ after do
225
+ variables.each_key do |key|
226
+ described_class.instance_variable_set(:"@#{key}", nil)
227
+ end
228
+ end
229
+
230
+ let(:schema) do
231
+ Lutaml::Xsd.parse(<<~XSD)
232
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
233
+ <xsd:element name="test_element"/>
234
+ <xsd:attribute name="test_attribute" type="xsd:string"/>
235
+ <xsd:group name="test_group"/>
236
+ <xsd:simpleType name="test_simple_type"/>
237
+ <xsd:complexType name="test_complex_type" mixed="true"/>
238
+ <xsd:attributeGroup name="test_attribute_group"/>
239
+ </xsd:schema>
240
+ XSD
241
+ end
242
+
243
+ let(:variables) do
244
+ {
245
+ elements: { "test_element" => { element_name: "test_element", type_name: nil } },
246
+ attributes: { "test_attribute" => { name: "test_attribute", base_class: "xsd:string" } },
247
+ group_types: { "test_group" => {} },
248
+ simple_types: { "test_simple_type" => {} },
249
+ complex_types: { "test_complex_type" => { mixed: true } },
250
+ attribute_groups: { "test_attribute_group" => {} },
251
+ }
252
+ end
253
+
254
+ it "initializes the instance variables with empty MappingHash" do
255
+ described_class.send(:schema_to_models, [schema])
256
+ variables.each do |variable, expected_value|
257
+ instance_variable = described_class.instance_variable_get(:"@#{variable}")
258
+ expect(instance_variable).to be_a(Lutaml::Model::MappingHash)
259
+ expect(instance_variable).to eql(expected_value)
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ describe ".setup_simple_type" do
266
+ context "when given simple_type contains restriction and union" do
267
+ let(:simple_type) do
268
+ Lutaml::Xsd::SimpleType.new.tap do |st|
269
+ st.restriction = Lutaml::Xsd::RestrictionSimpleType.new(base: "test_base")
270
+ st.union = Lutaml::Xsd::Union.new(member_types: "")
271
+ end
272
+ end
273
+
274
+ it "initializes the instance variables with empty MappingHash" do
275
+ expect(described_class.send(:setup_simple_type, simple_type)).to eql({ base_class: "test_base", union: [] })
276
+ end
277
+ end
278
+
279
+ context "when simple_type contains nothing" do
280
+ let(:simple_type) { Lutaml::Xsd::SimpleType.new }
281
+
282
+ it "initializes the instance variables with empty MappingHash" do
283
+ expect(described_class.send(:setup_simple_type, simple_type)).to eql({})
284
+ end
285
+ end
286
+ end
287
+
288
+ describe ".restriction_content" do
289
+ context "when given restriction contains max_length, min_length, min_inclusive, max_inclusive, length" do
290
+ let(:restriction) do
291
+ Lutaml::Xsd::RestrictionSimpleType.new.tap do |r|
292
+ r.max_length = [Lutaml::Xsd::MaxLength.new(value: "10")]
293
+ r.min_length = [Lutaml::Xsd::MinLength.new(value: "1")]
294
+ r.min_inclusive = [Lutaml::Xsd::MinInclusive.new(value: "1")]
295
+ r.max_inclusive = [Lutaml::Xsd::MaxInclusive.new(value: "10")]
296
+ r.length = [Lutaml::Xsd::Length.new(value: "10")]
297
+ end
298
+ end
299
+
300
+ it "initializes the instance variables with empty MappingHash" do
301
+ described_class.send(:restriction_content, hash = {}, restriction)
302
+ expect(hash).to eql({ max_length: 10, min_length: 1, min_inclusive: "1", max_inclusive: "10", length: [{ value: 10 }] })
303
+ end
304
+ end
305
+
306
+ context "when restriction contains nothing" do
307
+ let(:restriction) { Lutaml::Xsd::RestrictionSimpleType.new }
308
+
309
+ it "initializes the instance variables with empty MappingHash" do
310
+ described_class.send(:restriction_content, hash = {}, restriction)
311
+ expect(hash).to be_empty
312
+ end
313
+ end
314
+ end
315
+
316
+ describe ".restriction_length" do
317
+ context "when given restriction contains max_length, min_length, min_inclusive, max_inclusive, length" do
318
+ let(:lengths) do
319
+ [
320
+ Lutaml::Xsd::Length.new(value: "10", fixed: true),
321
+ Lutaml::Xsd::Length.new(value: "1"),
322
+ Lutaml::Xsd::Length.new(value: "1", fixed: true),
323
+ Lutaml::Xsd::Length.new(value: "10"),
324
+ Lutaml::Xsd::Length.new(value: "10", fixed: true),
325
+ ]
326
+ end
327
+
328
+ let(:expected_content) do
329
+ [
330
+ { value: 10, fixed: true },
331
+ { value: 1 },
332
+ { value: 1, fixed: true },
333
+ { value: 10 },
334
+ { value: 10, fixed: true },
335
+ ]
336
+ end
337
+
338
+ it "initializes the instance variables with empty MappingHash" do
339
+ expect(described_class.send(:restriction_length, lengths)).to eql(expected_content)
340
+ end
341
+ end
342
+
343
+ context "when restriction contains nothing" do
344
+ it "initializes the instance variables with empty MappingHash" do
345
+ expect(described_class.send(:restriction_length, [])).to be_empty
346
+ end
347
+ end
348
+ end
349
+
350
+ describe ".setup_complex_type" do
351
+ context "when given complex_type contains attribute, sequence, choice, complex_content, attribute_group, group, simple_content" do
352
+ let(:complex_type) do
353
+ Lutaml::Xsd::ComplexType.new.tap do |ct|
354
+ ct.attribute = [Lutaml::Xsd::Attribute.new(type: "test_attribute", name: "test_attribute1")]
355
+ ct.sequence = [Lutaml::Xsd::Sequence.new(name: "test_sequence")]
356
+ ct.choice = [Lutaml::Xsd::Choice.new(name: "test_choice")]
357
+ ct.complex_content = [Lutaml::Xsd::ComplexContent.new(name: "test_complex_content")]
358
+ ct.attribute_group = [Lutaml::Xsd::AttributeGroup.new(name: "test_attribute_group")]
359
+ ct.group = [Lutaml::Xsd::Group.new(name: "test_group")]
360
+ ct.simple_content = [Lutaml::Xsd::SimpleContent.new(name: "test_simple_content")]
361
+ ct.element_order = create_pattern_mapping([
362
+ ["Element", "attribute"],
363
+ ["Element", "sequence"],
364
+ ["Element", "choice"],
365
+ ["Element", "complex_content"],
366
+ ["Element", "attribute_group"],
367
+ ["Element", "group"],
368
+ ["Element", "simple_content"],
369
+ ])
370
+ end
371
+ end
372
+
373
+ let(:expected_hash) do
374
+ {
375
+ attributes: [{ name: "test_attribute1", base_class: "test_attribute" }],
376
+ sequence: {},
377
+ choice: {},
378
+ complex_content: {},
379
+ attribute_groups: [{}],
380
+ group: {},
381
+ mixed: false,
382
+ simple_content: nil,
383
+ }
384
+ end
385
+
386
+ it "initializes the instance variables with empty MappingHash" do
387
+ expect(described_class.send(:setup_complex_type, complex_type)).to eql(expected_hash)
388
+ end
389
+ end
390
+
391
+ context "when restriction contains nothing" do
392
+ let(:complex_type) do
393
+ Lutaml::Xsd::ComplexType.new.tap do |ct|
394
+ ct.element_order = []
395
+ end
396
+ end
397
+
398
+ it "initializes the instance variables with empty MappingHash" do
399
+ expect(described_class.send(:setup_complex_type, complex_type)).to eq({ mixed: false })
400
+ end
401
+ end
402
+ end
403
+
404
+ describe ".setup_simple_content" do
405
+ context "when given complex_type contains extension" do
406
+ let(:complex_type) do
407
+ Lutaml::Xsd::SimpleContent.new.tap do |ct|
408
+ ct.extension = Lutaml::Xsd::ExtensionSimpleContent.new(base: "test_extension")
409
+ ct.element_order = [Lutaml::Model::XmlAdapter::Element.new("Element", "extension")]
410
+ end
411
+ end
412
+
413
+ let(:expected_hash) { { extension_base: "test_extension" } }
414
+
415
+ it "initializes the instance variables with empty MappingHash" do
416
+ expect(described_class.send(:setup_simple_content, complex_type)).to eql(expected_hash)
417
+ end
418
+ end
419
+
420
+ context "when complex_type contains restriction" do
421
+ let(:complex_type) do
422
+ Lutaml::Xsd::SimpleContent.new.tap do |ct|
423
+ ct.restriction = Lutaml::Xsd::RestrictionSimpleContent.new(base: "test_restriction")
424
+ ct.element_order = [Lutaml::Model::XmlAdapter::Element.new("Element", "restriction")]
425
+ end
426
+ end
427
+
428
+ it "initializes the instance variables with empty MappingHash" do
429
+ expect(described_class.send(:setup_simple_content, complex_type)).to eql({ base_class: "test_restriction" })
430
+ end
431
+ end
432
+ end
433
+
434
+ describe ".setup_sequence" do
435
+ context "when given sequence contains sequence, element, choice, group" do
436
+ let(:sequence) do
437
+ Lutaml::Xsd::Sequence.new.tap do |ct|
438
+ ct.sequence = [Lutaml::Xsd::Sequence.new(name: "test_sequence")]
439
+ ct.element = [
440
+ Lutaml::Xsd::Element.new(name: "test_element"),
441
+ Lutaml::Xsd::Element.new(ref: "test_ref"),
442
+ ]
443
+ ct.choice = [Lutaml::Xsd::Choice.new(name: "test_choice")]
444
+ ct.group = [
445
+ Lutaml::Xsd::Group.new(name: "test_group"),
446
+ Lutaml::Xsd::Group.new(ref: "test_ref"),
447
+ ]
448
+ ct.element_order = create_pattern_mapping([
449
+ ["Element", "sequence"],
450
+ ["Element", "group"],
451
+ ["Element", "element"],
452
+ ["Element", "choice"],
453
+ ["Element", "element"],
454
+ ["Element", "group"],
455
+ ])
456
+ end
457
+ end
458
+
459
+ let(:expected_hash) do
460
+ {
461
+ sequences: [{}],
462
+ elements: [{ element_name: "test_element", type_name: nil }, { ref_class: "test_ref" }],
463
+ choice: [{}],
464
+ groups: [{}, { ref_class: "test_ref" }],
465
+ }
466
+ end
467
+
468
+ it "initializes the instance variables with empty MappingHash" do
469
+ expect(described_class.send(:setup_sequence, sequence)).to eql(expected_hash)
470
+ end
471
+ end
472
+
473
+ context "when sequence contains nothing" do
474
+ let(:sequence) do
475
+ Lutaml::Xsd::Sequence.new.tap do |ct|
476
+ ct.element_order = []
477
+ end
478
+ end
479
+
480
+ it "initializes the instance variables with empty MappingHash" do
481
+ expect(described_class.send(:setup_sequence, sequence)).to be_empty
482
+ end
483
+ end
484
+ end
485
+
486
+ describe ".setup_group_type" do
487
+ context "when given group contains sequence, choice" do
488
+ let(:group) do
489
+ Lutaml::Xsd::Group.new.tap do |ct|
490
+ ct.sequence = [Lutaml::Xsd::Sequence.new(name: "test_sequence")]
491
+ ct.choice = [Lutaml::Xsd::Choice.new(name: "test_choice")]
492
+ ct.element_order = create_pattern_mapping([
493
+ ["Element", "sequence"],
494
+ ["Element", "choice"],
495
+ ])
496
+ end
497
+ end
498
+
499
+ let(:expected_hash) { { sequence: {}, choice: {} } }
500
+
501
+ it "initializes the instance variables with empty MappingHash" do
502
+ expect(described_class.send(:setup_group_type, group)).to eql(expected_hash)
503
+ end
504
+ end
505
+
506
+ context "when sequence contains nothing" do
507
+ let(:group) do
508
+ Lutaml::Xsd::Group.new.tap do |ct|
509
+ ct.element_order = []
510
+ end
511
+ end
512
+
513
+ it "initializes the instance variables with empty MappingHash" do
514
+ expect(described_class.send(:setup_group_type, group)).to be_empty
515
+ end
516
+ end
517
+ end
518
+
519
+ describe ".setup_choice" do
520
+ context "when given choice contains sequence, choice" do
521
+ let(:choice) do
522
+ Lutaml::Xsd::Choice.new.tap do |ct|
523
+ ct.element = [Lutaml::Xsd::Element.new(name: "test_element")]
524
+ ct.sequence = [Lutaml::Xsd::Sequence.new(name: "test_sequence")]
525
+ ct.choice = [Lutaml::Xsd::Choice.new(name: "test_choice")]
526
+ ct.group = [Lutaml::Xsd::Group.new(name: "test_group")]
527
+ ct.element_order = create_pattern_mapping([
528
+ ["Element", "sequence"],
529
+ ["Element", "choice"],
530
+ ["Element", "group"],
531
+ ["Element", "element"],
532
+ ])
533
+ end
534
+ end
535
+
536
+ let(:expected_hash) { { sequence: {}, choice: {}, group: {}, "test_element" => { element_name: "test_element", type_name: nil } } }
537
+
538
+ it "initializes the instance variables with empty MappingHash" do
539
+ expect(described_class.send(:setup_choice, choice)).to eql(expected_hash)
540
+ end
541
+ end
542
+
543
+ context "when choice contains nothing" do
544
+ let(:choice) do
545
+ Lutaml::Xsd::Choice.new.tap do |ct|
546
+ ct.element_order = []
547
+ end
548
+ end
549
+
550
+ it "initializes the instance variables with empty MappingHash" do
551
+ expect(described_class.send(:setup_choice, choice)).to be_empty
552
+ end
553
+ end
554
+ end
555
+
556
+ describe ".setup_union" do
557
+ context "when given union contains member_types" do
558
+ before do
559
+ described_class.instance_variable_set(:@simple_types, simple_types)
560
+ end
561
+
562
+ after do
563
+ described_class.instance_variable_set(:@simple_types, nil)
564
+ end
565
+
566
+ let(:simple_types) do
567
+ {
568
+ "test_member_type" => { name: "test_member_type" },
569
+ "test_member_type1" => { name: "test_member_type1" },
570
+ }
571
+ end
572
+
573
+ let(:union) do
574
+ Lutaml::Xsd::Union.new.tap do |ct|
575
+ ct.member_types = "test_member_type test_member_type1"
576
+ end
577
+ end
578
+
579
+ let(:expected_hash) { [{ name: "test_member_type" }, { name: "test_member_type1" }] }
580
+
581
+ it "returns the expected hash" do
582
+ expect(described_class.send(:setup_union, union)).to eql(expected_hash)
583
+ end
584
+ end
585
+
586
+ context "when union contains nothing" do
587
+ let(:union) { Lutaml::Xsd::Union.new }
588
+
589
+ it "returns the empty hash" do
590
+ expect(described_class.send(:setup_union, union)).to be_empty
591
+ end
592
+ end
593
+ end
594
+
595
+ describe ".setup_attribute" do
596
+ context "when given attribute contains name and type" do
597
+ let(:attribute) do
598
+ Lutaml::Xsd::Attribute.new.tap do |attr|
599
+ attr.name = "test_name"
600
+ attr.type = "test_type"
601
+ end
602
+ end
603
+
604
+ let(:expected_hash) { { name: "test_name", base_class: "test_type" } }
605
+
606
+ it "returns the expected hash" do
607
+ expect(described_class.send(:setup_attribute, attribute)).to eql(expected_hash)
608
+ end
609
+ end
610
+
611
+ context "when given attribute contains ref" do
612
+ let(:attribute) do
613
+ Lutaml::Xsd::Attribute.new.tap do |attr|
614
+ attr.ref = "test_ref"
615
+ end
616
+ end
617
+
618
+ let(:expected_hash) { { ref_class: "test_ref" } }
619
+
620
+ it "returns the expected hash" do
621
+ expect(described_class.send(:setup_attribute, attribute)).to eql(expected_hash)
622
+ end
623
+ end
624
+
625
+ context "when attribute contains nothing" do
626
+ let(:attribute) { Lutaml::Xsd::Attribute.new }
627
+ let(:expected_hash) { { name: nil, base_class: nil } }
628
+
629
+ it "returns the empty hash" do
630
+ expect(described_class.send(:setup_attribute, attribute)).to eql(expected_hash)
631
+ end
632
+ end
633
+ end
634
+
635
+ describe ".setup_attribute_groups" do
636
+ context "when given attribute_group contains attribute and attribute_group" do
637
+ let(:attribute_group) do
638
+ Lutaml::Xsd::AttributeGroup.new.tap do |attr_group|
639
+ attr_group.attribute = [Lutaml::Xsd::Attribute.new(name: "test_name", type: "test_type")]
640
+ attr_group.attribute_group = [Lutaml::Xsd::AttributeGroup.new(name: "test_name", type: "test_type")]
641
+ attr_group.element_order = create_pattern_mapping([
642
+ ["Element", "attribute"],
643
+ ["Element", "attribute_group"],
644
+ ])
645
+ end
646
+ end
647
+
648
+ let(:expected_hash) { { attributes: [{ name: "test_name", base_class: "test_type" }], attribute_groups: [{}] } }
649
+
650
+ it "returns the expected hash" do
651
+ expect(described_class.send(:setup_attribute_groups, attribute_group)).to eql(expected_hash)
652
+ end
653
+ end
654
+
655
+ context "when given attribute_group contains ref" do
656
+ let(:attribute_group) do
657
+ Lutaml::Xsd::AttributeGroup.new.tap do |attr_group|
658
+ attr_group.ref = "test_ref"
659
+ end
660
+ end
661
+
662
+ let(:expected_hash) { { ref_class: "test_ref" } }
663
+
664
+ it "returns the expected hash" do
665
+ expect(described_class.send(:setup_attribute_groups, attribute_group)).to eql(expected_hash)
666
+ end
667
+ end
668
+
669
+ context "when attribute_group contains nothing" do
670
+ let(:attribute_group) { Lutaml::Xsd::AttributeGroup.new }
671
+
672
+ it "returns the empty hash" do
673
+ expect(described_class.send(:setup_attribute_groups, attribute_group)).to be_empty
674
+ end
675
+ end
676
+ end
677
+
678
+ describe ".create_mapping_hash" do
679
+ context "when given value is a string and hash_key is :class_name" do
680
+ let(:value) { "test_value" }
681
+ let(:expected_hash) { { class_name: "test_value" } }
682
+
683
+ it "returns the expected hash" do
684
+ expect(described_class.send(:create_mapping_hash, value, hash_key: :class_name)).to eql(expected_hash)
685
+ end
686
+ end
687
+
688
+ context "when given value is a string and hash_key is :element_name" do
689
+ let(:value) { "test_value" }
690
+ let(:expected_hash) { { element_name: "test_value" } }
691
+
692
+ it "returns the expected hash" do
693
+ expect(described_class.send(:create_mapping_hash, value, hash_key: :element_name)).to eql(expected_hash)
694
+ end
695
+ end
696
+
697
+ context "when given value is a array and hash_key is :ref_class" do
698
+ let(:value) { ["test_value"] }
699
+ let(:expected_hash) { { ref_class: ["test_value"] } }
700
+
701
+ it "returns the expected hash" do
702
+ expect(described_class.send(:create_mapping_hash, value, hash_key: :ref_class)).to eql(expected_hash)
703
+ end
704
+ end
705
+
706
+ context "when given value is a string and hash_key is not given" do
707
+ let(:value) { "test_value" }
708
+ let(:expected_hash) { { class_name: "test_value" } }
709
+
710
+ it "returns the expected hash" do
711
+ expect(described_class.send(:create_mapping_hash, value)).to eql(expected_hash)
712
+ end
713
+ end
714
+ end
715
+
716
+ describe ".setup_element" do
717
+ before do
718
+ described_class.instance_variable_set(:@complex_types, complex_types)
719
+ end
720
+
721
+ after do
722
+ described_class.instance_variable_set(:@complex_types, nil)
723
+ end
724
+
725
+ let(:complex_types) { { "test_complex_type" => {} } }
726
+
727
+ context "when given element contains ref" do
728
+ let(:element) do
729
+ Lutaml::Xsd::Element.new.tap do |element|
730
+ element.ref = "test_ref"
731
+ end
732
+ end
733
+
734
+ let(:expected_hash) { { ref_class: "test_ref" } }
735
+
736
+ it "returns the expected hash" do
737
+ expect(described_class.send(:setup_element, element)).to eql(expected_hash)
738
+ end
739
+ end
740
+
741
+ context "when given element contains ref with other attributes/elements" do
742
+ let(:element) do
743
+ Lutaml::Xsd::Element.new.tap do |element|
744
+ element.ref = "test_ref"
745
+ element.type = "test_type"
746
+ element.name = "test_name"
747
+ element.min_occurs = 0
748
+ element.max_occurs = 1
749
+ element.complex_type = Lutaml::Xsd::ComplexType.new(name: "test_complex_type")
750
+ element.element_order = [Lutaml::Model::XmlAdapter::Element.new("Element", "complex_type")]
751
+ end
752
+ end
753
+
754
+ let(:expected_hash) { { ref_class: "test_ref" } }
755
+
756
+ it "returns the expected hash" do
757
+ expect(described_class.send(:setup_element, element)).to eql(expected_hash)
758
+ end
759
+ end
760
+
761
+ context "when given element contains type, name and min/max_occurs" do
762
+ let(:element) do
763
+ Lutaml::Xsd::Element.new.tap do |element|
764
+ element.type = "test_type"
765
+ element.name = "test_name"
766
+ element.min_occurs = 0
767
+ element.max_occurs = 1
768
+ end
769
+ end
770
+
771
+ let(:expected_hash) { { type_name: "test_type", element_name: "test_name", arguments: { min_occurs: "0", max_occurs: "1" } } }
772
+
773
+ it "returns the expected hash" do
774
+ expect(described_class.send(:setup_element, element)).to eql(expected_hash)
775
+ end
776
+ end
777
+
778
+ context "when given element contains name, type, and complex_type and no min/max_occurs" do
779
+ let(:element) do
780
+ Lutaml::Xsd::Element.new.tap do |element|
781
+ element.type = "test_type"
782
+ element.name = "test_name"
783
+ element.complex_type = Lutaml::Xsd::ComplexType.new(name: "test_complex_type")
784
+ element.element_order = [Lutaml::Model::XmlAdapter::Element.new("Element", "complex_type")]
785
+ end
786
+ end
787
+
788
+ let(:expected_hash) { { type_name: "test_type", element_name: "test_name", complex_type: { mixed: false } } }
789
+
790
+ it "returns the expected hash" do
791
+ expect(described_class.send(:setup_element, element)).to eql(expected_hash)
792
+ end
793
+ end
794
+
795
+ context "when given element contains nothing" do
796
+ let(:element) { Lutaml::Xsd::Element.new }
797
+ let(:expected_hash) { { type_name: nil, element_name: nil } }
798
+
799
+ it "returns the expected hash" do
800
+ expect(described_class.send(:setup_element, element)).to eql(expected_hash)
801
+ end
802
+ end
803
+ end
804
+
805
+ describe ".setup_restriction" do
806
+ context "when given restriction contains base and pattern" do
807
+ let(:restriction) do
808
+ Lutaml::Xsd::RestrictionSimpleType.new.tap do |restriction|
809
+ restriction.base = "test_base"
810
+ restriction.pattern = [
811
+ Lutaml::Xsd::Pattern.new(value: /test_pattern/),
812
+ Lutaml::Xsd::Pattern.new(value: /test_pattern1/),
813
+ ]
814
+ restriction.enumeration = [
815
+ Lutaml::Xsd::Enumeration.new(value: "test_value"),
816
+ Lutaml::Xsd::Enumeration.new(value: "test_value1"),
817
+ ]
818
+ end
819
+ end
820
+
821
+ let(:expected_hash) { { base_class: "test_base", pattern: "((?-mix:test_pattern))|((?-mix:test_pattern1))", values: ["test_value", "test_value1"] } }
822
+
823
+ it "returns the expected hash" do
824
+ expect(described_class.send(:setup_restriction, restriction, {})).to eql(expected_hash)
825
+ end
826
+ end
827
+
828
+ context "when given restriction contains nothing" do
829
+ let(:restriction) { Lutaml::Xsd::RestrictionSimpleType.new }
830
+
831
+ it "returns the expected hash" do
832
+ expect(described_class.send(:setup_restriction, restriction, {})).to eql({ base_class: nil })
833
+ end
834
+ end
835
+ end
836
+
837
+ describe ".restriction_patterns" do
838
+ context "when given patterns are not empty" do
839
+ let(:patterns) do
840
+ [
841
+ Lutaml::Xsd::Pattern.new(value: /test_pattern/),
842
+ Lutaml::Xsd::Pattern.new(value: /test_pattern1/),
843
+ ]
844
+ end
845
+
846
+ let(:expected_hash) { { pattern: "((?-mix:test_pattern))|((?-mix:test_pattern1))" } }
847
+
848
+ it "returns the expected hash" do
849
+ expect(described_class.send(:restriction_patterns, patterns, {})).to eql(expected_hash)
850
+ end
851
+ end
852
+
853
+ context "when given patterns are empty" do
854
+ let(:patterns) { [] }
855
+
856
+ it "returns the expected hash" do
857
+ expect(described_class.send(:restriction_patterns, patterns, {})).to be_nil
858
+ end
859
+ end
860
+ end
861
+
862
+ describe ".setup_complex_content" do
863
+ context "when given complex_content contains extension with mixed attribute" do
864
+ let(:complex_content) do
865
+ Lutaml::Xsd::ComplexContent.new.tap do |complex_content|
866
+ complex_content.mixed = true
867
+ complex_content.extension = Lutaml::Xsd::ExtensionComplexContent.new(base: "test_base")
868
+ end
869
+ end
870
+
871
+ let(:expected_hash) { { mixed: true, extension: { extension_base: "test_base" } } }
872
+
873
+ it "returns the expected hash" do
874
+ expect(described_class.send(:setup_complex_content, complex_content)).to eql(expected_hash)
875
+ end
876
+ end
877
+
878
+ context "when given complex_content contains restriction" do
879
+ let(:complex_content) do
880
+ Lutaml::Xsd::ComplexContent.new.tap do |complex_content|
881
+ complex_content.restriction = Lutaml::Xsd::RestrictionComplexContent.new(base: "test_base")
882
+ end
883
+ end
884
+
885
+ let(:expected_hash) { { base_class: "test_base" } }
886
+
887
+ it "returns the expected hash" do
888
+ expect(described_class.send(:setup_complex_content, complex_content)).to eql(expected_hash)
889
+ end
890
+ end
891
+ end
892
+
893
+ describe ".setup_extension" do
894
+ context "when given extension contains attributes" do
895
+ let(:extension) do
896
+ Lutaml::Xsd::ExtensionComplexContent.new.tap do |extension|
897
+ extension.base = "test_base"
898
+ extension.attribute = [
899
+ Lutaml::Xsd::Attribute.new(type: "ST_Attr1", name: "Attr1", default: "1"),
900
+ Lutaml::Xsd::Attribute.new(type: "ST_Attr2", name: "Attr2", default: "2"),
901
+ ]
902
+ extension.sequence = Lutaml::Xsd::Sequence.new
903
+ extension.choice = Lutaml::Xsd::Choice.new
904
+ extension.element_order = create_pattern_mapping([
905
+ ["Element", "attribute"],
906
+ ["Element", "sequence"],
907
+ ["Element", "choice"],
908
+ ["Element", "attribute"],
909
+ ])
910
+ end
911
+ end
912
+
913
+ let(:expected_hash) do
914
+ {
915
+ extension_base: "test_base",
916
+ attributes: [{ base_class: "ST_Attr1", name: "Attr1", default: "1" }, { base_class: "ST_Attr2", name: "Attr2", default: "2" }],
917
+ sequence: {},
918
+ choice: {},
919
+ }
920
+ end
921
+
922
+ it "returns the expected hash" do
923
+ expect(described_class.send(:setup_extension, extension)).to eql(expected_hash)
924
+ end
925
+ end
926
+
927
+ context "when given extension contains nothing" do
928
+ let(:extension) { Lutaml::Xsd::ExtensionComplexContent.new }
929
+
930
+ it "returns the expected hash" do
931
+ expect(described_class.send(:setup_extension, extension)).to eql({ extension_base: nil })
932
+ end
933
+ end
934
+ end
935
+
936
+ describe ".element_arguments" do
937
+ context "when given element contains min_occurs and max_occurs" do
938
+ let(:element) do
939
+ Lutaml::Xsd::Element.new.tap do |element|
940
+ element.min_occurs = "0"
941
+ element.max_occurs = "1"
942
+ end
943
+ end
944
+
945
+ let(:expected_hash) { { min_occurs: "0", max_occurs: "1" } }
946
+
947
+ it "returns the expected hash" do
948
+ expect(described_class.send(:element_arguments, element, {})).to eql(expected_hash)
949
+ end
950
+ end
951
+
952
+ context "when given element contains nothing" do
953
+ let(:element) { Lutaml::Xsd::Element.new }
954
+
955
+ it "returns the expected hash" do
956
+ expect(described_class.send(:element_arguments, element, {})).to be_empty
957
+ end
958
+ end
959
+ end
960
+
961
+ describe ".resolved_element_order" do
962
+ context "when given element contains element_order but no instance relevant elements/instances" do
963
+ let(:element) do
964
+ Lutaml::Xsd::Element.new.tap do |element|
965
+ element.element_order = create_pattern_mapping([
966
+ ["Element", "annotation"],
967
+ ["Element", "simple_type"],
968
+ ["Element", "complex_type"],
969
+ ["Element", "key"],
970
+ ])
971
+ end
972
+ end
973
+
974
+ it "raises an error when element_order contains elements that isn't an attribute of the instance" do
975
+ element.element_order << Lutaml::Model::XmlAdapter::Element.new("Element", "test_element")
976
+ expect { described_class.send(:resolved_element_order, element) }.to raise_error(NoMethodError)
977
+ end
978
+
979
+ it "returns the array with nil values" do
980
+ expected_hash = [nil, nil, nil, nil]
981
+ expect(described_class.send(:resolved_element_order, element)).to eql(expected_hash)
982
+ end
983
+ end
984
+
985
+ context "when given element contains element_order but with relevant elements/instances" do
986
+ let(:element) do
987
+ Lutaml::Xsd::Element.new.tap do |element|
988
+ element.annotation = Lutaml::Xsd::Annotation.new
989
+ element.simple_type = Lutaml::Xsd::SimpleType.new
990
+ element.complex_type = Lutaml::Xsd::ComplexType.new
991
+ element.key = Lutaml::Xsd::Key.new
992
+ element.element_order = create_pattern_mapping([
993
+ ["Element", "annotation"],
994
+ ["Element", "simple_type"],
995
+ ["Element", "complex_type"],
996
+ ["Element", "key"],
997
+ ])
998
+ end
999
+ end
1000
+
1001
+ let(:expected_hash) { [element.annotation, element.simple_type, element.complex_type, element.key] }
1002
+
1003
+ it "returns the expected hash" do
1004
+ expect(described_class.send(:resolved_element_order, element)).to eql(expected_hash)
1005
+ end
1006
+ end
1007
+
1008
+ context "when given element contains empty element_order with elements/instances" do
1009
+ let(:element) do
1010
+ Lutaml::Xsd::Element.new.tap do |element|
1011
+ element.element_order = []
1012
+ end
1013
+ end
1014
+
1015
+ it "returns the expected hash" do
1016
+ expect(described_class.send(:resolved_element_order, element)).to be_empty
1017
+ end
1018
+ end
1019
+ end
1020
+ end
1021
+
1022
+ describe "structure to template content resolving methods" do
1023
+ describe ".resolve_parent_class" do
1024
+ context "when complex_content.extension is not present" do
1025
+ it "returns Lutaml::Model::Serializable" do
1026
+ expect(described_class.send(:resolve_parent_class, {})).to eql("Lutaml::Model::Serializable")
1027
+ end
1028
+ end
1029
+
1030
+ context "when complex_content.extension is present" do
1031
+ it "returns the extension_base value" do
1032
+ content = { complex_content: { extension: { extension_base: "ST_Parent" } } }
1033
+ expect(described_class.send(:resolve_parent_class, content)).to eql("STParent")
1034
+ end
1035
+ end
1036
+ end
1037
+
1038
+ describe ".resolve_attribute_class" do
1039
+ context "when attribute.base_class is one of the standard classes" do
1040
+ described_class::DEFAULT_CLASSES.each do |standard_class|
1041
+ it "returns the attribute_class value for #{standard_class.capitalize}" do
1042
+ base_class_hash = to_mapping_hash({ base_class: "xsd:#{standard_class}" })
1043
+ expect(described_class.send(:resolve_attribute_class, base_class_hash)).to eql(":#{standard_class}")
1044
+ end
1045
+ end
1046
+ end
1047
+
1048
+ context "when attribute.base_class is not one of the standard classes" do
1049
+ it "returns the attribute_class value" do
1050
+ base_class_hash = to_mapping_hash({ base_class: "test_st_attr1" })
1051
+ expect(described_class.send(:resolve_attribute_class, base_class_hash)).to eql("TestStAttr1")
1052
+ end
1053
+ end
1054
+ end
1055
+
1056
+ describe ".resolve_element_class" do
1057
+ context "when element.type_name is one of the standard classes" do
1058
+ described_class::DEFAULT_CLASSES.each do |standard_class|
1059
+ it "returns the element_class value for #{standard_class.capitalize}" do
1060
+ type_name_hash = to_mapping_hash({ type_name: "xsd:#{standard_class}" })
1061
+ expect(described_class.send(:resolve_element_class, type_name_hash)).to eql(":#{standard_class}")
1062
+ end
1063
+ end
1064
+ end
1065
+
1066
+ context "when element.type_name is not one of the standard classes" do
1067
+ it "returns the element_class value" do
1068
+ type_name_hash = to_mapping_hash({ type_name: "test_st_element1" })
1069
+ expect(described_class.send(:resolve_element_class, type_name_hash)).to eql("TestStElement1")
1070
+ end
1071
+ end
1072
+ end
1073
+
1074
+ describe ".resolve_occurs" do
1075
+ context "when min_occurs and max_occurs are present" do
1076
+ it "returns the collection: true" do
1077
+ base_class_hash = to_mapping_hash({ min_occurs: 0, max_occurs: "unbounded" })
1078
+ expect(described_class.send(:resolve_occurs, base_class_hash)).to eql(", collection: true")
1079
+ end
1080
+
1081
+ it "returns the collection: 0..1" do
1082
+ base_class_hash = to_mapping_hash({ min_occurs: 0, max_occurs: 1 })
1083
+ expect(described_class.send(:resolve_occurs, base_class_hash)).to eql(", collection: 0..1")
1084
+ end
1085
+ end
1086
+
1087
+ context "when min_occurs/max_occurs are not present" do
1088
+ it "returns the collection: 0.." do
1089
+ base_class_hash = to_mapping_hash({ min_occurs: 0, max_occurs: 1 })
1090
+ expect(described_class.send(:resolve_occurs, base_class_hash)).to eql(", collection: 0..1")
1091
+ end
1092
+ end
1093
+ end
1094
+
1095
+ describe ".resolve_elements" do
1096
+ before do
1097
+ described_class.instance_variable_set(:@elements, elements)
1098
+ end
1099
+
1100
+ after do
1101
+ described_class.instance_variable_set(:@elements, nil)
1102
+ end
1103
+
1104
+ let(:elements) do
1105
+ to_mapping_hash({ "testRef" => to_mapping_hash({ element_name: "testElement" }) })
1106
+ end
1107
+
1108
+ context "when elements contain ref_class and base_class elements" do
1109
+ it "returns the elements hash" do
1110
+ content = [to_mapping_hash({ ref_class: "testRef" }), to_mapping_hash({ element_name: "testElement1" })]
1111
+ expected_elements = { "testElement" => { element_name: "testElement" }, "testElement1" => { element_name: "testElement1" } }
1112
+ expect(described_class.send(:resolve_elements, content)).to eql(expected_elements)
1113
+ end
1114
+ end
1115
+ end
1116
+
1117
+ describe ".resolve_content" do
1118
+ let(:content) do
1119
+ {
1120
+ sequence: [],
1121
+ choice: [],
1122
+ group: [],
1123
+ }
1124
+ end
1125
+
1126
+ context "when content contain empty sequence, choice and group" do
1127
+ it "returns the elements hash" do
1128
+ expect(described_class.send(:resolve_content, content)).to be_empty
1129
+ end
1130
+ end
1131
+ end
1132
+
1133
+ describe ".resolve_sequence" do
1134
+ let(:sequence) do
1135
+ {
1136
+ sequence: [],
1137
+ elements: [],
1138
+ groups: [],
1139
+ choice: [],
1140
+ }
1141
+ end
1142
+
1143
+ context "when sequence contain empty elements and other empty attributes" do
1144
+ it "returns the elements empty hash" do
1145
+ expect(described_class.send(:resolve_sequence, sequence)).to be_empty
1146
+ end
1147
+ end
1148
+ end
1149
+
1150
+ describe ".resolve_choice" do
1151
+ let(:choice) do
1152
+ {
1153
+ "string" => to_mapping_hash({ element_name: "testElement" }),
1154
+ sequence: [],
1155
+ element: [],
1156
+ group: [],
1157
+ }
1158
+ end
1159
+
1160
+ context "when choice contain empty elements and other empty attributes" do
1161
+ it "returns the one element hash" do
1162
+ expect(described_class.send(:resolve_choice, choice)).to eql({ "string" => { element_name: "testElement" } })
1163
+ end
1164
+ end
1165
+ end
1166
+
1167
+ describe ".resolve_group" do
1168
+ before do
1169
+ described_class.instance_variable_set(:@group_types, group_types)
1170
+ end
1171
+
1172
+ after do
1173
+ described_class.instance_variable_set(:@group_types, nil)
1174
+ end
1175
+
1176
+ let(:group_types) { { "testRef" => {} } }
1177
+
1178
+ let(:group) do
1179
+ {
1180
+ ref_class: "testRef",
1181
+ sequence: [],
1182
+ choice: [],
1183
+ group: [],
1184
+ }
1185
+ end
1186
+
1187
+ context "when group contain ref_class and other empty attributes" do
1188
+ it "returns the one element hash" do
1189
+ expect(described_class.send(:resolve_group, group)).to be_empty
1190
+ end
1191
+ end
1192
+ end
1193
+
1194
+ describe ".resolve_complex_content" do
1195
+ let(:complex_content) do
1196
+ {
1197
+ extension: {},
1198
+ restriction: {},
1199
+ }
1200
+ end
1201
+
1202
+ context "when complex_content contain extension and restriction" do
1203
+ it "returns the one element hash" do
1204
+ expect(described_class.send(:resolve_complex_content, complex_content)).to be_empty
1205
+ end
1206
+ end
1207
+ end
1208
+
1209
+ describe ".resolve_extension" do
1210
+ let(:extension) do
1211
+ {
1212
+ attributes: [{ base_class: "ST_Attr1", default: "1" }, { base_class: "ST_Attr2", default: "2" }],
1213
+ sequence: {},
1214
+ choice: {},
1215
+ }
1216
+ end
1217
+
1218
+ context "when extension contain attributes, sequence and choice" do
1219
+ it "returns the one element hash" do
1220
+ expect(described_class.send(:resolve_extension, to_mapping_hash(extension))).to eql({ attributes: extension[:attributes] })
1221
+ end
1222
+ end
1223
+ end
1224
+
1225
+ describe ".resolve_attribute_default" do
1226
+ context "when attribute contain default" do
1227
+ it "returns the string with default value" do
1228
+ attribute = to_mapping_hash({ base_class: "ST_Attr1", default: "1" })
1229
+ expect(described_class.send(:resolve_attribute_default, attribute)).to eql(", default: \"1\"")
1230
+ end
1231
+ end
1232
+
1233
+ context "when attribute contain no default" do
1234
+ it "returns the string with nil as default value" do
1235
+ attribute = to_mapping_hash({ base_class: "ST_Attr1" })
1236
+ expect(described_class.send(:resolve_attribute_default, attribute)).to eql(", default: nil")
1237
+ end
1238
+ end
1239
+ end
1240
+
1241
+ describe ".resolve_attribute_default_value" do
1242
+ context "when attribute data type is one of the standard classes" do
1243
+ let(:standard_class_value) do
1244
+ {
1245
+ "int" => { input: "1", output: 1 },
1246
+ "integer" => { input: "12", output: 12 },
1247
+ "string" => { input: "test_string", output: "test_string" },
1248
+ "boolean" => { input: "false", output: false },
1249
+ }
1250
+ end
1251
+
1252
+ described_class::DEFAULT_CLASSES.each do |standard_class|
1253
+ it "returns the value as the #{standard_class.capitalize} class instance" do
1254
+ default_value = standard_class_value[standard_class]
1255
+ expect(described_class.send(:resolve_attribute_default_value, standard_class, default_value[:input])).to eql(default_value[:output])
1256
+ end
1257
+ end
1258
+ end
1259
+
1260
+ context "when attribute data type is not one of the standard classes" do
1261
+ it "returns the string with default value" do
1262
+ expect(described_class.send(:resolve_attribute_default_value, "BooleanTestClass", "1")).to eql("\"1\"")
1263
+ end
1264
+ end
1265
+ end
1266
+
1267
+ describe ".resolve_namespace" do
1268
+ context "when namespace is given" do
1269
+ it "returns the string with namespace" do
1270
+ expect(described_class.send(:resolve_namespace, { namespace: "testNamespace" })).to eql("namespace \"testNamespace\"\n")
1271
+ end
1272
+ end
1273
+
1274
+ context "when namespace and prefix are given" do
1275
+ it "returns the string with namespace and prefix" do
1276
+ expect(described_class.send(:resolve_namespace, { namespace: "testNamespace", prefix: "testPrefix" })).to eql("namespace \"testNamespace\", \"testPrefix\"\n")
1277
+ end
1278
+ end
1279
+
1280
+ context "when namespace and prefix are not given" do
1281
+ it "returns the string with nil" do
1282
+ expect(described_class.send(:resolve_namespace, {})).to be_nil
1283
+ end
1284
+ end
1285
+ end
1286
+ end
1287
+
1288
+ describe "required files list compiler methods" do
1289
+ describe ".resolve_required_files" do
1290
+ context "when elements are given" do
1291
+ before do
1292
+ described_class.instance_variable_set(:@required_files, [])
1293
+ end
1294
+
1295
+ after do
1296
+ described_class.instance_variable_set(:@required_files, nil)
1297
+ end
1298
+
1299
+ let(:content) do
1300
+ {
1301
+ attribute_groups: {},
1302
+ complex_content: {},
1303
+ simple_content: {},
1304
+ attributes: {},
1305
+ sequence: {},
1306
+ choice: {},
1307
+ group: {},
1308
+ }
1309
+ end
1310
+
1311
+ it "populates @required_files variable with the names of the required files" do
1312
+ described_class.send(:resolve_required_files, content)
1313
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1314
+ end
1315
+ end
1316
+ end
1317
+
1318
+ describe ".required_files_simple_content" do
1319
+ context "when elements are given" do
1320
+ before do
1321
+ described_class.instance_variable_set(:@required_files, [])
1322
+ end
1323
+
1324
+ after do
1325
+ described_class.instance_variable_set(:@required_files, nil)
1326
+ end
1327
+
1328
+ let(:content) do
1329
+ {
1330
+ extension_base: {},
1331
+ attributes: {},
1332
+ extension: {},
1333
+ restriction: {},
1334
+ }
1335
+ end
1336
+
1337
+ it "populates @required_files variable with the names of the required files" do
1338
+ described_class.send(:required_files_simple_content, content)
1339
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1340
+ end
1341
+ end
1342
+ end
1343
+
1344
+ describe ".required_files_complex_content" do
1345
+ context "when elements are given" do
1346
+ before do
1347
+ described_class.instance_variable_set(:@required_files, [])
1348
+ end
1349
+
1350
+ after do
1351
+ described_class.instance_variable_set(:@required_files, nil)
1352
+ end
1353
+
1354
+ let(:content) do
1355
+ {
1356
+ extension: {},
1357
+ restriction: {},
1358
+ }
1359
+ end
1360
+
1361
+ it "populates @required_files variable with the names of the required files" do
1362
+ described_class.send(:required_files_complex_content, content)
1363
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1364
+ end
1365
+ end
1366
+ end
1367
+
1368
+ describe ".required_files_extension" do
1369
+ context "when elements are given" do
1370
+ before do
1371
+ described_class.instance_variable_set(:@required_files, [])
1372
+ end
1373
+
1374
+ after do
1375
+ described_class.instance_variable_set(:@required_files, nil)
1376
+ end
1377
+
1378
+ let(:content) do
1379
+ {
1380
+ attribute_group: {},
1381
+ extension_base: {},
1382
+ attributes: {},
1383
+ attribute: {},
1384
+ sequence: {},
1385
+ choice: {},
1386
+ }
1387
+ end
1388
+
1389
+ it "populates @required_files variable with the names of the required files" do
1390
+ described_class.send(:required_files_extension, content)
1391
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1392
+ end
1393
+ end
1394
+ end
1395
+
1396
+ describe ".required_files_restriction" do
1397
+ context "when elements are given" do
1398
+ before do
1399
+ described_class.instance_variable_set(:@required_files, [])
1400
+ end
1401
+
1402
+ after do
1403
+ described_class.instance_variable_set(:@required_files, nil)
1404
+ end
1405
+
1406
+ let(:content) { { base: "testId" } }
1407
+
1408
+ it "populates @required_files variable with the names of the required files" do
1409
+ described_class.send(:required_files_restriction, content)
1410
+ expect(described_class.instance_variable_get(:@required_files)).to eql(["test_id"])
1411
+ end
1412
+ end
1413
+ end
1414
+
1415
+ describe ".required_files_attribute_groups" do
1416
+ context "when elements are given" do
1417
+ before do
1418
+ described_class.instance_variable_set(:@required_files, [])
1419
+ described_class.instance_variable_set(:@attribute_groups, attribute_groups)
1420
+ end
1421
+
1422
+ after do
1423
+ described_class.instance_variable_set(:@required_files, nil)
1424
+ described_class.instance_variable_set(:@attribute_groups, nil)
1425
+ end
1426
+
1427
+ let(:attribute_groups) { { "testId" => {} } }
1428
+
1429
+ let(:content) do
1430
+ {
1431
+ ref_class: "testId",
1432
+ attributes: {},
1433
+ attribute: {},
1434
+ }
1435
+ end
1436
+
1437
+ it "populates @required_files variable with the names of the required files" do
1438
+ described_class.send(:required_files_attribute_groups, content)
1439
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1440
+ end
1441
+ end
1442
+ end
1443
+
1444
+ describe ".required_files_attribute" do
1445
+ context "when elements are given" do
1446
+ before do
1447
+ described_class.instance_variable_set(:@required_files, [])
1448
+ described_class.instance_variable_set(:@attributes, attributes)
1449
+ end
1450
+
1451
+ after do
1452
+ described_class.instance_variable_set(:@required_files, nil)
1453
+ described_class.instance_variable_set(:@attributes, nil)
1454
+ end
1455
+
1456
+ let(:attributes) do
1457
+ {
1458
+ "testRef" => to_mapping_hash({ base_class: "ST_Attr1" }),
1459
+ }
1460
+ end
1461
+
1462
+ let(:content) do
1463
+ [
1464
+ to_mapping_hash({ ref_class: "testRef" }),
1465
+ to_mapping_hash({ base_class: "ST_Attr2" }),
1466
+ ]
1467
+ end
1468
+
1469
+ it "populates @required_files variable with the names of the required files" do
1470
+ described_class.send(:required_files_attribute, content)
1471
+ expect(described_class.instance_variable_get(:@required_files)).to eql(["st_attr1", "st_attr2"])
1472
+ end
1473
+ end
1474
+ end
1475
+
1476
+ describe ".required_files_choice" do
1477
+ context "when elements are given" do
1478
+ before { described_class.instance_variable_set(:@required_files, []) }
1479
+ after { described_class.instance_variable_set(:@required_files, nil) }
1480
+
1481
+ let(:content) do
1482
+ {
1483
+ "testRef" => to_mapping_hash({ type_name: "ST_Attr1" }),
1484
+ sequence: {},
1485
+ element: {},
1486
+ choice: {},
1487
+ group: {},
1488
+ }
1489
+ end
1490
+
1491
+ it "populates @required_files variable with the names of the required files" do
1492
+ described_class.send(:required_files_choice, content)
1493
+ expect(described_class.instance_variable_get(:@required_files)).to eql(["st_attr1"])
1494
+ end
1495
+ end
1496
+ end
1497
+
1498
+ describe ".required_files_group" do
1499
+ context "when elements are given" do
1500
+ before do
1501
+ described_class.instance_variable_set(:@required_files, [])
1502
+ described_class.instance_variable_set(:@group_types, group_types)
1503
+ end
1504
+
1505
+ after do
1506
+ described_class.instance_variable_set(:@required_files, nil)
1507
+ described_class.instance_variable_set(:@group_types, nil)
1508
+ end
1509
+
1510
+ let(:group_types) { { "testRef" => {} } }
1511
+ let(:content) do
1512
+ {
1513
+ ref_class: "testRef",
1514
+ sequence: {},
1515
+ choice: {},
1516
+ }
1517
+ end
1518
+
1519
+ it "populates @required_files variable with the names of the required files" do
1520
+ described_class.send(:required_files_group, content)
1521
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1522
+ end
1523
+ end
1524
+ end
1525
+
1526
+ describe ".required_files_sequence" do
1527
+ context "when elements are given" do
1528
+ before do
1529
+ described_class.instance_variable_set(:@required_files, [])
1530
+ end
1531
+
1532
+ after do
1533
+ described_class.instance_variable_set(:@required_files, nil)
1534
+ end
1535
+
1536
+ let(:content) do
1537
+ {
1538
+ elements: {},
1539
+ sequence: {},
1540
+ groups: {},
1541
+ choice: {},
1542
+ }
1543
+ end
1544
+
1545
+ it "populates @required_files variable with the names of the required files" do
1546
+ described_class.send(:required_files_sequence, content)
1547
+ expect(described_class.instance_variable_get(:@required_files)).to eql([])
1548
+ end
1549
+ end
1550
+ end
1551
+
1552
+ describe ".required_files_elements" do
1553
+ context "when given element's data type is not one of standard class" do
1554
+ before do
1555
+ described_class.instance_variable_set(:@required_files, [])
1556
+ described_class.instance_variable_set(:@elements, elements)
1557
+ end
1558
+
1559
+ after do
1560
+ described_class.instance_variable_set(:@required_files, nil)
1561
+ described_class.instance_variable_set(:@elements, nil)
1562
+ end
1563
+
1564
+ let(:elements) do
1565
+ {
1566
+ "CT_Element1" => to_mapping_hash({ type_name: "w:CT_Element1" }),
1567
+ }
1568
+ end
1569
+
1570
+ let(:content) do
1571
+ [
1572
+ to_mapping_hash({ ref_class: "CT_Element1" }),
1573
+ to_mapping_hash({ type_name: "CT_Element2" }),
1574
+ ]
1575
+ end
1576
+
1577
+ it "populates @required_files variable with the names of the required files" do
1578
+ described_class.send(:required_files_elements, content)
1579
+ expect(described_class.instance_variable_get(:@required_files)).to eql(["ct_element1", "ct_element2"])
1580
+ end
1581
+ end
1582
+
1583
+ context "when given element's data type is one of standard class" do
1584
+ before do
1585
+ described_class.instance_variable_set(:@required_files, [])
1586
+ described_class.instance_variable_set(:@elements, elements)
1587
+ end
1588
+
1589
+ after do
1590
+ described_class.instance_variable_set(:@required_files, nil)
1591
+ described_class.instance_variable_set(:@elements, nil)
1592
+ end
1593
+
1594
+ let(:elements) do
1595
+ {
1596
+ "CT_Element1" => to_mapping_hash({ type_name: "w:CT_Element1" }),
1597
+ "CT_Element2" => to_mapping_hash({ type_name: "xsd:string" }),
1598
+ }
1599
+ end
1600
+
1601
+ let(:content) do
1602
+ [
1603
+ to_mapping_hash({ type_name: "CT_Element1" }),
1604
+ to_mapping_hash({ ref_class: "CT_Element2" }),
1605
+ ]
1606
+ end
1607
+
1608
+ it "populates @required_files variable with the names of the required files excluding default classes" do
1609
+ described_class.send(:required_files_elements, content)
1610
+ expect(described_class.instance_variable_get(:@required_files)).to eql(["ct_element1"])
1611
+ end
1612
+ end
1613
+ end
1614
+ end
1615
+ end
1616
+
1617
+ def create_pattern_mapping(array)
1618
+ array.map { |type, text| Lutaml::Model::XmlAdapter::Element.new(type, text) }
1619
+ end
1620
+
1621
+ def to_mapping_hash(content)
1622
+ @hash ||= Lutaml::Model::MappingHash.new
1623
+ @hash.merge(content)
1624
+ end