lutaml-model 0.3.23 → 0.3.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +35 -16
- data/README.adoc +274 -28
- data/lib/lutaml/model/attribute.rb +18 -8
- data/lib/lutaml/model/error/type_error.rb +9 -0
- data/lib/lutaml/model/error/unknown_type_error.rb +9 -0
- data/lib/lutaml/model/error/validation_error.rb +0 -1
- data/lib/lutaml/model/error.rb +2 -0
- data/lib/lutaml/model/serialize.rb +7 -2
- data/lib/lutaml/model/type/boolean.rb +38 -0
- data/lib/lutaml/model/type/date.rb +35 -0
- data/lib/lutaml/model/type/date_time.rb +32 -4
- data/lib/lutaml/model/type/decimal.rb +42 -0
- data/lib/lutaml/model/type/float.rb +37 -0
- data/lib/lutaml/model/type/hash.rb +62 -0
- data/lib/lutaml/model/type/integer.rb +41 -0
- data/lib/lutaml/model/type/string.rb +49 -0
- data/lib/lutaml/model/type/time.rb +49 -0
- data/lib/lutaml/model/type/time_without_date.rb +37 -5
- data/lib/lutaml/model/type/value.rb +52 -0
- data/lib/lutaml/model/type.rb +50 -114
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml_adapter/builder/nokogiri.rb +5 -2
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +2 -1
- data/lib/lutaml/model/xml_adapter/xml_document.rb +0 -2
- data/lutaml-model.gemspec +1 -1
- data/spec/address_spec.rb +170 -0
- data/spec/fixtures/address.rb +33 -0
- data/spec/fixtures/person.rb +73 -0
- data/spec/fixtures/sample_model.rb +40 -0
- data/spec/fixtures/vase.rb +38 -0
- data/spec/fixtures/xml/special_char.xml +13 -0
- data/spec/lutaml/model/attribute_spec.rb +112 -0
- data/spec/lutaml/model/collection_spec.rb +299 -0
- data/spec/lutaml/model/comparable_model_spec.rb +106 -0
- data/spec/lutaml/model/custom_model_spec.rb +410 -0
- data/spec/lutaml/model/custom_serialization_spec.rb +170 -0
- data/spec/lutaml/model/defaults_spec.rb +221 -0
- data/spec/lutaml/model/delegation_spec.rb +340 -0
- data/spec/lutaml/model/inheritance_spec.rb +92 -0
- data/spec/lutaml/model/json_adapter_spec.rb +37 -0
- data/spec/lutaml/model/key_value_mapping_spec.rb +86 -0
- data/spec/lutaml/model/map_content_spec.rb +118 -0
- data/spec/lutaml/model/mixed_content_spec.rb +625 -0
- data/spec/lutaml/model/namespace_spec.rb +57 -0
- data/spec/lutaml/model/ordered_content_spec.rb +83 -0
- data/spec/lutaml/model/render_nil_spec.rb +138 -0
- data/spec/lutaml/model/schema/json_schema_spec.rb +79 -0
- data/spec/lutaml/model/schema/relaxng_schema_spec.rb +60 -0
- data/spec/lutaml/model/schema/xsd_schema_spec.rb +55 -0
- data/spec/lutaml/model/schema/yaml_schema_spec.rb +47 -0
- data/spec/lutaml/model/serializable_spec.rb +297 -0
- data/spec/lutaml/model/serializable_validation_spec.rb +85 -0
- data/spec/lutaml/model/simple_model_spec.rb +314 -0
- data/spec/lutaml/model/toml_adapter_spec.rb +39 -0
- data/spec/lutaml/model/type/boolean_spec.rb +54 -0
- data/spec/lutaml/model/type/date_spec.rb +118 -0
- data/spec/lutaml/model/type/date_time_spec.rb +127 -0
- data/spec/lutaml/model/type/decimal_spec.rb +125 -0
- data/spec/lutaml/model/type/float_spec.rb +191 -0
- data/spec/lutaml/model/type/hash_spec.rb +63 -0
- data/spec/lutaml/model/type/integer_spec.rb +145 -0
- data/spec/lutaml/model/type/string_spec.rb +150 -0
- data/spec/lutaml/model/type/time_spec.rb +142 -0
- data/spec/lutaml/model/type/time_without_date_spec.rb +125 -0
- data/spec/lutaml/model/type_spec.rb +276 -0
- data/spec/lutaml/model/utils_spec.rb +79 -0
- data/spec/lutaml/model/validation_spec.rb +83 -0
- data/spec/lutaml/model/with_child_mapping_spec.rb +174 -0
- data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +56 -0
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +56 -0
- data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +61 -0
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +251 -0
- data/spec/lutaml/model/xml_adapter_spec.rb +178 -0
- data/spec/lutaml/model/xml_mapping_spec.rb +863 -0
- data/spec/lutaml/model/yaml_adapter_spec.rb +30 -0
- data/spec/lutaml/model_spec.rb +1 -0
- data/spec/person_spec.rb +161 -0
- data/spec/spec_helper.rb +33 -0
- metadata +66 -2
@@ -0,0 +1,56 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "oga"
|
3
|
+
require_relative "../../../../lib/lutaml/model/xml_adapter/oga_adapter"
|
4
|
+
|
5
|
+
RSpec.xdescribe Lutaml::Model::XmlAdapter::OgaAdapter do
|
6
|
+
let(:xml_string) do
|
7
|
+
<<~XML
|
8
|
+
<root xmlns="http://example.com/default" xmlns:prefix="http://example.com/prefixed">
|
9
|
+
<prefix:child attr="value" prefix:attr="prefixed_value">Text</prefix:child>
|
10
|
+
</root>
|
11
|
+
XML
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:document) { described_class.parse(xml_string) }
|
15
|
+
|
16
|
+
context "parsing XML with namespaces" do
|
17
|
+
it "parses the root element with default namespace" do
|
18
|
+
expect(document.root.name).to eq("root")
|
19
|
+
expect(document.root.namespace).to eq("http://example.com/default")
|
20
|
+
expect(document.root.namespace_prefix).to be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "parses child element with prefixed namespace" do
|
24
|
+
child = document.root.children.first
|
25
|
+
expect(child.name).to eq("child")
|
26
|
+
expect(child.namespace).to eq("http://example.com/prefixed")
|
27
|
+
expect(child.namespace_prefix).to eq("prefix")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "parses attributes with and without namespaces" do
|
31
|
+
child = document.root.children.first
|
32
|
+
expect(child.attributes["attr"].value).to eq("value")
|
33
|
+
expect(child.attributes["attr"].namespace).to be_nil
|
34
|
+
expect(child.attributes["prefix:attr"].value).to eq("prefixed_value")
|
35
|
+
expect(child.attributes["prefix:attr"].namespace).to eq("http://example.com/prefixed")
|
36
|
+
expect(child.attributes["prefix:attr"].namespace_prefix).to eq("prefix")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "generating XML with namespaces" do
|
41
|
+
it "generates XML with namespaces correctly" do
|
42
|
+
xml_output = document.to_xml
|
43
|
+
parsed_output = Oga.parse_xml(xml_output)
|
44
|
+
|
45
|
+
root = parsed_output.root
|
46
|
+
expect(root.name).to eq("root")
|
47
|
+
expect(root.namespace.uri).to eq("http://example.com/default")
|
48
|
+
|
49
|
+
child = root.children.first
|
50
|
+
expect(child.name).to eq("child")
|
51
|
+
expect(child.namespace.uri).to eq("http://example.com/prefixed")
|
52
|
+
expect(child.get("attr")).to eq("value")
|
53
|
+
expect(child.get("prefix:attr")).to eq("prefixed_value")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "ox"
|
3
|
+
require_relative "../../../../lib/lutaml/model/xml_adapter/ox_adapter"
|
4
|
+
|
5
|
+
RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
|
6
|
+
let(:xml_string) do
|
7
|
+
<<-XML
|
8
|
+
<root xmlns="http://example.com/default" xmlns:prefix="http://example.com/prefixed">
|
9
|
+
<prefix:child attr="value" prefix:attr="prefixed_value">Text</prefix:child>
|
10
|
+
<!-- just-a-comment -->
|
11
|
+
</root>
|
12
|
+
XML
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:document) { described_class.parse(xml_string) }
|
16
|
+
|
17
|
+
context "parsing XML with namespaces" do
|
18
|
+
it "parses the root element with default namespace" do
|
19
|
+
expect(document.root.name).to eq("root")
|
20
|
+
expect(document.root.namespace.uri).to eq("http://example.com/default")
|
21
|
+
expect(document.root.namespace.prefix).to be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "parses child element with prefixed namespace" do
|
25
|
+
child = document.root.children.first
|
26
|
+
expect(child.name).to eq("prefix:child")
|
27
|
+
expect(child.namespace.uri).to eq("http://example.com/prefixed")
|
28
|
+
expect(child.namespace.prefix).to eq("prefix")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "parses comment" do
|
32
|
+
expect(document.root.nodes.last.text).to eq("just-a-comment")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "parses attributes with and without namespaces" do
|
36
|
+
child = document.root.children.first
|
37
|
+
expect(child.attributes["attr"].value).to eq("value")
|
38
|
+
expect(child.attributes["attr"].namespace).to be_nil
|
39
|
+
expect(child.attributes["prefix:attr"].value).to eq("prefixed_value")
|
40
|
+
expect(child.attributes["prefix:attr"].namespace).to eq("http://example.com/prefixed")
|
41
|
+
expect(child.attributes["prefix:attr"].namespace_prefix).to eq("prefix")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "generating XML with namespaces" do
|
46
|
+
it "generates XML with namespaces correctly" do
|
47
|
+
xml_output = document.to_xml
|
48
|
+
parsed_output = Ox.parse(xml_output)
|
49
|
+
|
50
|
+
root = parsed_output
|
51
|
+
expect(root.name).to eq("root")
|
52
|
+
expect(root.attributes[:xmlns]).to eq("http://example.com/default")
|
53
|
+
expect(root.attributes[:"xmlns:prefix"]).to eq("http://example.com/prefixed")
|
54
|
+
|
55
|
+
child = root.nodes.first
|
56
|
+
expect(child.name).to eq("prefix:child")
|
57
|
+
expect(child.attributes[:attr]).to eq("value")
|
58
|
+
expect(child.attributes[:"prefix:attr"]).to eq("prefixed_value")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "lutaml/model/xml_adapter/nokogiri_adapter"
|
3
|
+
require "lutaml/model/xml_adapter/ox_adapter"
|
4
|
+
require "lutaml/model/xml_adapter/oga_adapter"
|
5
|
+
require "lutaml/model"
|
6
|
+
|
7
|
+
RSpec.shared_context "XML namespace models" do
|
8
|
+
class TestModelNoPrefix < Lutaml::Model::Serializable
|
9
|
+
attribute :name, :string
|
10
|
+
|
11
|
+
xml do
|
12
|
+
root "test"
|
13
|
+
namespace "http://example.com/test", "test"
|
14
|
+
map_element "name", to: :name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class TestModelWithPrefix < Lutaml::Model::Serializable
|
19
|
+
attribute :name, :string
|
20
|
+
|
21
|
+
xml do
|
22
|
+
root "test"
|
23
|
+
namespace "http://example.com/test", "test"
|
24
|
+
map_element "name", to: :name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class SamplePrefixedNamespacedModel < Lutaml::Model::Serializable
|
29
|
+
attribute :id, :string
|
30
|
+
attribute :lang, :string
|
31
|
+
attribute :name, :string, default: -> { "Anonymous" }
|
32
|
+
attribute :age, :integer, default: -> { 18 }
|
33
|
+
|
34
|
+
xml do
|
35
|
+
root "SamplePrefixedNamespacedModel"
|
36
|
+
namespace "http://example.com/foo", "foo"
|
37
|
+
|
38
|
+
map_attribute "id", to: :id
|
39
|
+
map_attribute "lang", to: :lang,
|
40
|
+
prefix: "xml",
|
41
|
+
namespace: "http://example.com/xml"
|
42
|
+
|
43
|
+
map_element "Name", to: :name, prefix: "bar", namespace: "http://example.com/bar"
|
44
|
+
map_element "Age", to: :age, prefix: "baz", namespace: "http://example.com/baz"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class NamespaceNilPrefixedNamespaced < Lutaml::Model::Serializable
|
49
|
+
attribute :namespace_model, SamplePrefixedNamespacedModel
|
50
|
+
|
51
|
+
xml do
|
52
|
+
root "NamespaceNil"
|
53
|
+
map_element "SamplePrefixedNamespacedModel", to: :namespace_model,
|
54
|
+
namespace: nil,
|
55
|
+
prefix: nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class SampleDefaultNamespacedModel < Lutaml::Model::Serializable
|
60
|
+
attribute :id, :string
|
61
|
+
attribute :lang, :string
|
62
|
+
attribute :name, :string, default: -> { "Anonymous" }
|
63
|
+
attribute :age, :integer, default: -> { 18 }
|
64
|
+
|
65
|
+
xml do
|
66
|
+
root "SampleDefaultNamespacedModel"
|
67
|
+
namespace "http://example.com/foo"
|
68
|
+
|
69
|
+
map_attribute "id", to: :id
|
70
|
+
map_attribute "lang", to: :lang,
|
71
|
+
prefix: "xml",
|
72
|
+
namespace: "http://example.com/xml"
|
73
|
+
|
74
|
+
map_element "Name", to: :name, prefix: "bar", namespace: "http://example.com/bar"
|
75
|
+
map_element "Age", to: :age, prefix: "baz", namespace: "http://example.com/baz"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class NamespaceNilDefaultNamespaced < Lutaml::Model::Serializable
|
80
|
+
attribute :namespace_model, SampleDefaultNamespacedModel
|
81
|
+
|
82
|
+
xml do
|
83
|
+
root "NamespaceNil"
|
84
|
+
map_element "SampleDefaultNamespacedModel", to: :namespace_model,
|
85
|
+
namespace: nil,
|
86
|
+
prefix: nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
RSpec.shared_examples "XML serialization with namespace" do |model_class, xml_string|
|
92
|
+
it "serializes to XML" do
|
93
|
+
model = model_class.new(name: "Test Name")
|
94
|
+
expect(model.to_xml).to be_equivalent_to(xml_string)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "deserializes from XML" do
|
98
|
+
model = model_class.from_xml(xml_string)
|
99
|
+
expect(model.name).to eq("Test Name")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
RSpec.shared_examples "an XML namespace parser" do |adapter_class|
|
104
|
+
include_context "XML namespace models"
|
105
|
+
|
106
|
+
around do |example|
|
107
|
+
old_adapter = Lutaml::Model::Config.xml_adapter
|
108
|
+
Lutaml::Model::Config.xml_adapter = adapter_class
|
109
|
+
example.run
|
110
|
+
ensure
|
111
|
+
Lutaml::Model::Config.xml_adapter = old_adapter
|
112
|
+
end
|
113
|
+
|
114
|
+
context "with no prefix" do
|
115
|
+
include_examples "XML serialization with namespace",
|
116
|
+
TestModelNoPrefix,
|
117
|
+
'<test xmlns="http://example.com/test"><name>Test Name</name></test>'
|
118
|
+
end
|
119
|
+
|
120
|
+
context "with prefix" do
|
121
|
+
include_examples "XML serialization with namespace",
|
122
|
+
TestModelWithPrefix,
|
123
|
+
'<test:test xmlns:test="http://example.com/test"><test:name>Test Name</test:name></test:test>'
|
124
|
+
end
|
125
|
+
|
126
|
+
context "with prefixed namespace" do
|
127
|
+
let(:attributes) { { name: "John Doe", age: 30 } }
|
128
|
+
let(:model) { SamplePrefixedNamespacedModel.new(attributes) }
|
129
|
+
|
130
|
+
it "serializes to XML" do
|
131
|
+
expected_xml = <<~XML
|
132
|
+
<foo:SamplePrefixedNamespacedModel xmlns:foo="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
133
|
+
<bar:Name>John Doe</bar:Name>
|
134
|
+
<baz:Age>30</baz:Age>
|
135
|
+
</foo:SamplePrefixedNamespacedModel>
|
136
|
+
XML
|
137
|
+
|
138
|
+
expect(model.to_xml).to be_equivalent_to(expected_xml)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "deserializes from XML" do
|
142
|
+
xml = <<~XML
|
143
|
+
<foo:SamplePrefixedNamespacedModel xmlns:foo="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
144
|
+
<bar:Name>John Doe</bar:Name>
|
145
|
+
<baz:Age>30</baz:Age>
|
146
|
+
</foo:SamplePrefixedNamespacedModel>
|
147
|
+
XML
|
148
|
+
|
149
|
+
new_model = SamplePrefixedNamespacedModel.from_xml(xml)
|
150
|
+
expect(new_model.name).to eq("John Doe")
|
151
|
+
expect(new_model.age).to eq(30)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "round-trips if namespace is set" do
|
155
|
+
xml = <<~XML
|
156
|
+
<foo:SamplePrefixedNamespacedModel xml:lang="en" xmlns:foo="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
157
|
+
<bar:Name>John Doe</bar:Name>
|
158
|
+
<baz:Age>30</baz:Age>
|
159
|
+
</foo:SamplePrefixedNamespacedModel>
|
160
|
+
XML
|
161
|
+
|
162
|
+
doc = SamplePrefixedNamespacedModel.from_xml(xml)
|
163
|
+
generated_xml = doc.to_xml
|
164
|
+
expect(generated_xml).to be_equivalent_to(xml)
|
165
|
+
end
|
166
|
+
|
167
|
+
it "round-trips if namespace is set to nil in parent" do
|
168
|
+
xml = <<~XML
|
169
|
+
<NamespaceNil xmlns:foo="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
170
|
+
<SamplePrefixedNamespacedModel xml:lang="en">
|
171
|
+
<bar:Name>John Doe</bar:Name>
|
172
|
+
<baz:Age>30</baz:Age>
|
173
|
+
</SamplePrefixedNamespacedModel>
|
174
|
+
</NamespaceNil>
|
175
|
+
XML
|
176
|
+
|
177
|
+
doc = NamespaceNilPrefixedNamespaced.from_xml(xml)
|
178
|
+
generated_xml = doc.to_xml
|
179
|
+
expect(generated_xml).to be_equivalent_to(xml)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with default namespace" do
|
184
|
+
let(:attributes) { { name: "Jane Smith", age: 25 } }
|
185
|
+
let(:model) { SampleDefaultNamespacedModel.new(attributes) }
|
186
|
+
|
187
|
+
it "serializes to XML" do
|
188
|
+
expected_xml = <<~XML
|
189
|
+
<SampleDefaultNamespacedModel xmlns="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
190
|
+
<bar:Name>Jane Smith</bar:Name>
|
191
|
+
<baz:Age>25</baz:Age>
|
192
|
+
</SampleDefaultNamespacedModel>
|
193
|
+
XML
|
194
|
+
|
195
|
+
expect(model.to_xml).to be_equivalent_to(expected_xml)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "deserializes from XML" do
|
199
|
+
xml = <<~XML
|
200
|
+
<SampleDefaultNamespacedModel xmlns="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
201
|
+
<bar:Name>Jane Smith</bar:Name>
|
202
|
+
<baz:Age>25</baz:Age>
|
203
|
+
</SampleDefaultNamespacedModel>
|
204
|
+
XML
|
205
|
+
|
206
|
+
new_model = SampleDefaultNamespacedModel.from_xml(xml)
|
207
|
+
expect(new_model.name).to eq("Jane Smith")
|
208
|
+
expect(new_model.age).to eq(25)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "round-trips if namespace is set" do
|
212
|
+
xml = <<~XML
|
213
|
+
<SampleDefaultNamespacedModel xml:lang="en" xmlns="http://example.com/foo" xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
214
|
+
<bar:Name>Jane Smith</bar:Name>
|
215
|
+
<baz:Age>25</baz:Age>
|
216
|
+
</SampleDefaultNamespacedModel>
|
217
|
+
XML
|
218
|
+
|
219
|
+
doc = SampleDefaultNamespacedModel.from_xml(xml)
|
220
|
+
generated_xml = doc.to_xml
|
221
|
+
expect(generated_xml).to be_equivalent_to(xml)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "round-trips if namespace is set to nil in parent" do
|
225
|
+
xml = <<~XML
|
226
|
+
<NamespaceNil xmlns:bar="http://example.com/bar" xmlns:baz="http://example.com/baz">
|
227
|
+
<SampleDefaultNamespacedModel xml:lang="en">
|
228
|
+
<bar:Name>Jane Smith</bar:Name>
|
229
|
+
<baz:Age>25</baz:Age>
|
230
|
+
</SampleDefaultNamespacedModel>
|
231
|
+
</NamespaceNil>
|
232
|
+
XML
|
233
|
+
|
234
|
+
doc = NamespaceNilDefaultNamespaced.from_xml(xml)
|
235
|
+
generated_xml = doc.to_xml
|
236
|
+
expect(generated_xml).to be_equivalent_to(xml)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
RSpec.describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
|
242
|
+
it_behaves_like "an XML namespace parser", described_class
|
243
|
+
end
|
244
|
+
|
245
|
+
RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
|
246
|
+
it_behaves_like "an XML namespace parser", described_class
|
247
|
+
end
|
248
|
+
|
249
|
+
RSpec.xdescribe Lutaml::Model::XmlAdapter::OgaAdapter do
|
250
|
+
it_behaves_like "an XML namespace parser", described_class
|
251
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "lutaml/model/xml_adapter/nokogiri_adapter"
|
3
|
+
require "lutaml/model/xml_adapter/ox_adapter"
|
4
|
+
require "lutaml/model/xml_adapter/oga_adapter"
|
5
|
+
require_relative "../../fixtures/sample_model"
|
6
|
+
|
7
|
+
module XmlAdapterSpec
|
8
|
+
class Mstyle < Lutaml::Model::Serializable
|
9
|
+
attribute :displaystyle, :string, default: -> { "true" }
|
10
|
+
attribute :color, :string
|
11
|
+
attribute :finish, :string, default: -> { "yes" }
|
12
|
+
|
13
|
+
xml do
|
14
|
+
root "mstyle"
|
15
|
+
|
16
|
+
map_attribute :displaystyle, to: :displaystyle, render_default: true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Maths < Lutaml::Model::Serializable
|
21
|
+
attribute :display, :string, default: -> { "block" }
|
22
|
+
attribute :style, Mstyle, default: -> { Mstyle.new }
|
23
|
+
|
24
|
+
xml do
|
25
|
+
root "math"
|
26
|
+
|
27
|
+
map_attribute :display, to: :display
|
28
|
+
map_attribute "color", to: :color, delegate: :style
|
29
|
+
map_attribute "finish", to: :finish, delegate: :style,
|
30
|
+
render_default: true
|
31
|
+
map_element :mstyle, to: :style, render_default: true
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
RSpec.shared_examples "an XML adapter" do |adapter_class|
|
37
|
+
around do |example|
|
38
|
+
old_adapter = Lutaml::Model::Config.xml_adapter
|
39
|
+
Lutaml::Model::Config.xml_adapter = adapter_class
|
40
|
+
|
41
|
+
example.run
|
42
|
+
ensure
|
43
|
+
Lutaml::Model::Config.xml_adapter = old_adapter
|
44
|
+
end
|
45
|
+
|
46
|
+
before do
|
47
|
+
# Ensure BigDecimal is loaded because it is being used in sample model
|
48
|
+
require "bigdecimal"
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:attributes) { { name: "John Doe", age: 30 } }
|
52
|
+
let(:model) { SampleModel.new(attributes) }
|
53
|
+
|
54
|
+
context "with default value" do
|
55
|
+
it "set display attribute correctly, other attributes default" do
|
56
|
+
xml = "<math display='true'></math>"
|
57
|
+
|
58
|
+
parsed = XmlAdapterSpec::Maths.from_xml(xml)
|
59
|
+
expect(parsed.display).to eq("true")
|
60
|
+
expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
|
61
|
+
expect(parsed.style.displaystyle).to eq("true")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "set style attribute correctly, other attributes default" do
|
65
|
+
xml = "<math> <mstyle displaystyle='false'> </mstyle> </math>"
|
66
|
+
|
67
|
+
parsed = XmlAdapterSpec::Maths.from_xml(xml)
|
68
|
+
expect(parsed.display).to eq("block")
|
69
|
+
expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
|
70
|
+
expect(parsed.style.displaystyle).to eq("false")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "sets attributes default values" do
|
74
|
+
xml = "<math> </math>"
|
75
|
+
|
76
|
+
parsed = XmlAdapterSpec::Maths.from_xml(xml)
|
77
|
+
expect(parsed.display).to eq("block")
|
78
|
+
expect(parsed.style.class).to eq(XmlAdapterSpec::Mstyle)
|
79
|
+
expect(parsed.style.displaystyle).to eq("true")
|
80
|
+
end
|
81
|
+
|
82
|
+
it "delegate attributes with value" do
|
83
|
+
xml = "<math color='blue' finish='no'></math>"
|
84
|
+
|
85
|
+
parsed = XmlAdapterSpec::Maths.from_xml(xml)
|
86
|
+
expect(parsed.style.color).to eq("blue")
|
87
|
+
expect(parsed.style.finish).to eq("no")
|
88
|
+
expect(parsed.style.displaystyle).to eq("true")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "delegate attributes with one value" do
|
92
|
+
xml = "<math color='blue'></math>"
|
93
|
+
|
94
|
+
parsed = XmlAdapterSpec::Maths.from_xml(xml)
|
95
|
+
expect(parsed.style.color).to eq("blue")
|
96
|
+
expect(parsed.style.finish).to eq("yes")
|
97
|
+
expect(parsed.style.displaystyle).to eq("true")
|
98
|
+
end
|
99
|
+
|
100
|
+
it "delegate attributes with no value" do
|
101
|
+
xml = "<math></math>"
|
102
|
+
|
103
|
+
parsed = XmlAdapterSpec::Maths.from_xml(xml)
|
104
|
+
expect(parsed.style.color).to be_nil
|
105
|
+
expect(parsed.style.finish).to eq("yes")
|
106
|
+
expect(parsed.style.displaystyle).to eq("true")
|
107
|
+
end
|
108
|
+
|
109
|
+
it "round-trips XML and add default values" do
|
110
|
+
input_xml = <<~XML
|
111
|
+
<math display='true'></math>
|
112
|
+
XML
|
113
|
+
|
114
|
+
output_xml = <<~XML
|
115
|
+
<math display="true" finish="yes">
|
116
|
+
<mstyle displaystyle="true"/>
|
117
|
+
</math>
|
118
|
+
XML
|
119
|
+
|
120
|
+
parsed = XmlAdapterSpec::Maths.from_xml(input_xml)
|
121
|
+
|
122
|
+
expect(parsed.to_xml.strip).to eq(output_xml.strip)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it "serializes to XML" do
|
127
|
+
expected_xml = <<~XML
|
128
|
+
<SampleModel>
|
129
|
+
<Name>John Doe</Name>
|
130
|
+
<Age>30</Age>
|
131
|
+
</SampleModel>
|
132
|
+
XML
|
133
|
+
|
134
|
+
doc = adapter_class.parse(expected_xml)
|
135
|
+
xml = doc.to_xml
|
136
|
+
expect(xml).to be_equivalent_to(expected_xml)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "serializes to XML with only content" do
|
140
|
+
expected_xml = <<~XML
|
141
|
+
<Tag>
|
142
|
+
Bug
|
143
|
+
</Tag>
|
144
|
+
XML
|
145
|
+
|
146
|
+
doc = SampleModelTag.from_xml(expected_xml)
|
147
|
+
xml = doc.to_xml
|
148
|
+
expect(xml).to be_equivalent_to(expected_xml)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "deserializes from XML" do
|
152
|
+
xml = <<~XML
|
153
|
+
<SampleModel>
|
154
|
+
<Name>John Doe</Name>
|
155
|
+
<Age>30</Age>
|
156
|
+
</SampleModel>
|
157
|
+
XML
|
158
|
+
|
159
|
+
doc = adapter_class.parse(xml)
|
160
|
+
new_model = SampleModel.new(doc.root.children.to_h do |child|
|
161
|
+
[child.name.downcase.to_sym, child.text]
|
162
|
+
end)
|
163
|
+
expect(new_model.name).to eq("John Doe")
|
164
|
+
expect(new_model.age).to eq(30)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
RSpec.describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
|
169
|
+
it_behaves_like "an XML adapter", described_class
|
170
|
+
end
|
171
|
+
|
172
|
+
RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do
|
173
|
+
it_behaves_like "an XML adapter", described_class
|
174
|
+
end
|
175
|
+
|
176
|
+
RSpec.xdescribe Lutaml::Model::XmlAdapter::OgaAdapter do
|
177
|
+
it_behaves_like "an XML adapter", described_class
|
178
|
+
end
|