lutaml-model 0.5.0 → 0.5.2

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.
@@ -0,0 +1,297 @@
1
+ module RootMappingSpec
2
+ class CeramicDetails < Lutaml::Model::Serializable
3
+ attribute :name, :string
4
+ attribute :insignia, :string
5
+
6
+ key_value do
7
+ map "name", to: :name
8
+ map "insignia", to: :insignia
9
+ end
10
+ end
11
+
12
+ class CeramicWithDetails < Lutaml::Model::Serializable
13
+ attribute :ceramic_id, :string
14
+ attribute :ceramic_type, :string
15
+ attribute :ceramic_details, CeramicDetails
16
+ attribute :ceramic_urn, :string
17
+
18
+ key_value do
19
+ map "id", to: :ceramic_id
20
+ map "type", to: :ceramic_type
21
+ map "details", to: :ceramic_details
22
+ map "urn", to: :ceramic_urn
23
+ end
24
+ end
25
+
26
+ class CeramicCollectionWithKeyAndValue < Lutaml::Model::Serializable
27
+ attribute :ceramics, CeramicWithDetails, collection: true
28
+
29
+ key_value do
30
+ map to: :ceramics,
31
+ root_mappings: {
32
+ ceramic_id: :key,
33
+ ceramic_details: :value,
34
+ }
35
+ end
36
+ end
37
+
38
+ class CeramicCollectionWithKeyAndComplexValue < Lutaml::Model::Serializable
39
+ attribute :ceramics, CeramicWithDetails, collection: true
40
+
41
+ key_value do
42
+ map to: :ceramics,
43
+ root_mappings: {
44
+ ceramic_id: :key,
45
+ ceramic_type: :type,
46
+ ceramic_details: "details",
47
+ ceramic_urn: ["urn", "primary"],
48
+ }
49
+ end
50
+ end
51
+
52
+ class Ceramic < Lutaml::Model::Serializable
53
+ attribute :ceramic_id, :string
54
+ attribute :ceramic_name, :string
55
+
56
+ key_value do
57
+ map "id", to: :ceramic_id
58
+ map "name", to: :ceramic_name
59
+ end
60
+ end
61
+
62
+ class CeramicCollectionWithKeyOnly < Lutaml::Model::Serializable
63
+ attribute :ceramics, Ceramic, collection: true
64
+
65
+ key_value do
66
+ map to: :ceramics, root_mappings: { ceramic_id: :key }
67
+ end
68
+ end
69
+
70
+ class CeramicCollectionWithoutCollectionTrue < Lutaml::Model::Serializable
71
+ attribute :ceramics, Ceramic
72
+
73
+ key_value do
74
+ map to: :ceramics, root_mappings: { ceramic_id: :key }
75
+ end
76
+ end
77
+ end
78
+
79
+ RSpec.describe "RootMapping" do
80
+ shared_examples "having root mappings" do |format|
81
+ let(:adapter) do
82
+ Lutaml::Model::Config.public_send(:"#{format}_adapter")
83
+ end
84
+
85
+ let(:input) do
86
+ adapter.new(input_hash).public_send(:"to_#{format}")
87
+ end
88
+
89
+ # 1. Only map to `:key`. Then only override key, the rest of the mappings stay.
90
+ context "when only `key` is mapped" do
91
+ let(:parsed) do
92
+ RootMappingSpec::CeramicCollectionWithKeyOnly.public_send(:"from_#{format}", input)
93
+ end
94
+
95
+ let(:input_hash) do
96
+ {
97
+ "vase1" => { "name" => "Imperial Vase" },
98
+ "bowl2" => { "name" => "18th Century Bowl" },
99
+ }
100
+ end
101
+
102
+ let(:ceramic_vase) do
103
+ RootMappingSpec::Ceramic.new(
104
+ ceramic_id: "vase1",
105
+ ceramic_name: "Imperial Vase",
106
+ )
107
+ end
108
+
109
+ let(:ceramic_bowl) do
110
+ RootMappingSpec::Ceramic.new(
111
+ ceramic_id: "bowl2",
112
+ ceramic_name: "18th Century Bowl",
113
+ )
114
+ end
115
+
116
+ it "parses" do
117
+ expect(parsed.ceramics.count).to eq(2)
118
+ # Because Tomlib reverses the order of the hash, so can not check based on position
119
+ expect(parsed.ceramics).to include(ceramic_vase)
120
+ expect(parsed.ceramics).to include(ceramic_bowl)
121
+ end
122
+
123
+ describe "serialize" do
124
+ let(:collection) do
125
+ RootMappingSpec::CeramicCollectionWithKeyOnly.new(ceramics: [
126
+ ceramic_vase,
127
+ ceramic_bowl,
128
+ ])
129
+ end
130
+
131
+ it "serializes correctly" do
132
+ expect(collection.public_send(:"to_#{format}")).to eq(input)
133
+ end
134
+ end
135
+ end
136
+
137
+ # 2. Maps `:key` and another attribute, then we override all the other mappings (clean slate)
138
+ context "when `key` and `value` are mapped" do
139
+ let(:parsed) do
140
+ RootMappingSpec::CeramicCollectionWithKeyAndValue.public_send(:"from_#{format}", input)
141
+ end
142
+
143
+ let(:input_hash) do
144
+ {
145
+ "vase1" => { "name" => "Imperial Vase", "insignia" => "Tang Tianbao" },
146
+ "bowl2" => { "name" => "18th Century Bowl", "insignia" => "Ming Wanli" },
147
+ }
148
+ end
149
+
150
+ let(:vase_with_details) do
151
+ RootMappingSpec::CeramicWithDetails.new(
152
+ ceramic_id: "vase1",
153
+ ceramic_details: RootMappingSpec::CeramicDetails.new(
154
+ name: "Imperial Vase",
155
+ insignia: "Tang Tianbao",
156
+ ),
157
+ )
158
+ end
159
+
160
+ let(:bowl_with_details) do
161
+ RootMappingSpec::CeramicWithDetails.new(
162
+ ceramic_id: "bowl2",
163
+ ceramic_details: RootMappingSpec::CeramicDetails.new(
164
+ name: "18th Century Bowl",
165
+ insignia: "Ming Wanli",
166
+ ),
167
+ )
168
+ end
169
+
170
+ it "parses" do
171
+ expect(parsed.ceramics.count).to eq(2)
172
+ # Because Tomlib reverses the order of the hash, so can not check based on position
173
+ expect(parsed.ceramics).to include(vase_with_details)
174
+ expect(parsed.ceramics).to include(bowl_with_details)
175
+ end
176
+
177
+ describe "serialize" do
178
+ let(:collection) do
179
+ RootMappingSpec::CeramicCollectionWithKeyAndValue.new(ceramics: [
180
+ vase_with_details,
181
+ bowl_with_details,
182
+ ])
183
+ end
184
+
185
+ it "serializes correctly" do
186
+ expect(collection.public_send(:"to_#{format}")).to eq(input)
187
+ end
188
+ end
189
+ end
190
+
191
+ # 3. Maps `:key` and `:value`, then we map the key and the value body to the new mappings.
192
+ context "when `key` and complex value structure is mapped" do
193
+ let(:parsed) do
194
+ RootMappingSpec::CeramicCollectionWithKeyAndComplexValue.public_send(:"from_#{format}", input)
195
+ end
196
+
197
+ let(:input_hash) do
198
+ {
199
+ "vase1" => {
200
+ "type" => "vase",
201
+ "details" => {
202
+ "name" => "Imperial Vase",
203
+ "insignia" => "Tang Tianbao",
204
+ },
205
+ "urn" => {
206
+ "primary" => "urn:ceramic:vase:vase1",
207
+ },
208
+ },
209
+ "bowl2" => {
210
+ "type" => "bowl",
211
+ "details" => {
212
+ "name" => "18th Century Bowl",
213
+ "insignia" => "Ming Wanli",
214
+ },
215
+ "urn" => {
216
+ "primary" => "urn:ceramic:bowl:bowl2",
217
+ },
218
+ },
219
+ }
220
+ end
221
+
222
+ let(:vase_with_details) do
223
+ RootMappingSpec::CeramicWithDetails.new(
224
+ ceramic_id: "vase1",
225
+ ceramic_type: "vase",
226
+ ceramic_urn: "urn:ceramic:vase:vase1",
227
+ ceramic_details: RootMappingSpec::CeramicDetails.new(
228
+ name: "Imperial Vase",
229
+ insignia: "Tang Tianbao",
230
+ ),
231
+ )
232
+ end
233
+
234
+ let(:bowl_with_details) do
235
+ RootMappingSpec::CeramicWithDetails.new(
236
+ ceramic_id: "bowl2",
237
+ ceramic_type: "bowl",
238
+ ceramic_urn: "urn:ceramic:bowl:bowl2",
239
+ ceramic_details: RootMappingSpec::CeramicDetails.new(
240
+ name: "18th Century Bowl",
241
+ insignia: "Ming Wanli",
242
+ ),
243
+ )
244
+ end
245
+
246
+ it "parses" do
247
+ expect(parsed.ceramics.count).to eq(2)
248
+ # Because Tomlib reverses the order of the hash, so can not check based on position
249
+ expect(parsed.ceramics).to include(vase_with_details)
250
+ expect(parsed.ceramics).to include(bowl_with_details)
251
+ end
252
+
253
+ describe "serialize from object" do
254
+ let(:collection) do
255
+ RootMappingSpec::CeramicCollectionWithKeyAndComplexValue.new(ceramics: [
256
+ vase_with_details,
257
+ bowl_with_details,
258
+ ])
259
+ end
260
+
261
+ it "serializes correctly" do
262
+ expect(collection.public_send(:"to_#{format}")).to eq(input)
263
+ end
264
+ end
265
+ end
266
+
267
+ context "when `collection: true` is missing" do
268
+ let(:input_hash) do
269
+ {
270
+ "vase1" => { "name" => "Imperial Vase" },
271
+ "bowl2" => { "name" => "18th Century Bowl" },
272
+ }
273
+ end
274
+
275
+ it "raises error" do
276
+ expect do
277
+ RootMappingSpec::CeramicCollectionWithoutCollectionTrue.public_send(:"from_#{format}", input)
278
+ end.to raise_error(
279
+ Lutaml::Model::CollectionTrueMissingError,
280
+ "May be `collection: true` is missing for `ceramics` in RootMappingSpec::CeramicCollectionWithoutCollectionTrue",
281
+ )
282
+ end
283
+ end
284
+ end
285
+
286
+ describe Lutaml::Model::YamlAdapter::StandardYamlAdapter do
287
+ it_behaves_like "having root mappings", :yaml
288
+ end
289
+
290
+ describe Lutaml::Model::JsonAdapter::StandardJsonAdapter do
291
+ it_behaves_like "having root mappings", :json
292
+ end
293
+
294
+ describe Lutaml::Model::TomlAdapter::TomlRbAdapter do
295
+ it_behaves_like "having root mappings", :toml
296
+ end
297
+ end
@@ -77,6 +77,25 @@ module SerializeableSpec
77
77
  class GlazeTechnique < Lutaml::Model::Serializable
78
78
  attribute :name, :string, values: ["Celadon", "Raku", "Majolica"]
79
79
  end
80
+
81
+ class TranslateHelper < Lutaml::Model::Serializable
82
+ attribute :id, :string
83
+ attribute :path, :string
84
+ attribute :name, :string
85
+ end
86
+
87
+ class TranslateMappings < Lutaml::Model::Serializable
88
+ attribute :translate, TranslateHelper, collection: true
89
+
90
+ key_value do
91
+ map "translate", to: :translate, child_mappings:
92
+ {
93
+ id: :key,
94
+ path: %i[path link],
95
+ name: %i[path name],
96
+ }
97
+ end
98
+ end
80
99
  end
81
100
 
82
101
  RSpec.describe Lutaml::Model::Serializable do
@@ -173,7 +192,7 @@ RSpec.describe Lutaml::Model::Serializable do
173
192
  end
174
193
  end
175
194
 
176
- describe ".apply_child_mappings" do
195
+ describe ".translate_mappings" do
177
196
  let(:child_mappings) do
178
197
  {
179
198
  id: :key,
@@ -205,17 +224,33 @@ RSpec.describe Lutaml::Model::Serializable do
205
224
  }
206
225
  end
207
226
 
227
+ let(:attr) { SerializeableSpec::TranslateMappings.attributes[:translate] }
228
+
208
229
  let(:expected_value) do
209
230
  [
210
- { id: "foo", path: "link one", name: "one" },
211
- { id: "abc", path: "link two", name: "two" },
212
- { id: "hello", path: "link three", name: "three" },
231
+ SerializeableSpec::TranslateHelper.new({
232
+ "id" => "foo",
233
+ "name" => "one",
234
+ "path" => "link one",
235
+ }),
236
+ SerializeableSpec::TranslateHelper.new({
237
+ "id" => "abc",
238
+ "name" => "two",
239
+ "path" => "link two",
240
+ }),
241
+ SerializeableSpec::TranslateHelper.new({
242
+ "id" => "hello",
243
+ "name" => "three",
244
+ "path" => "link three",
245
+ }),
213
246
  ]
214
247
  end
215
248
 
216
249
  it "generates hash based on child_mappings" do
217
- expect(described_class.apply_child_mappings(hash,
218
- child_mappings)).to eq(expected_value)
250
+ actual_value = described_class.translate_mappings(hash, child_mappings, attr, :yaml)
251
+
252
+ expect(actual_value.map { |obj| [obj.id, obj.name, obj.path] })
253
+ .to eq(expected_value.map { |obj| [obj.id, obj.name, obj.path] })
219
254
  end
220
255
  end
221
256
 
@@ -37,6 +37,63 @@ module ChildMapping
37
37
  }
38
38
  end
39
39
  end
40
+
41
+ class JS < Lutaml::Model::Serializable
42
+ attribute :prop, :string
43
+ attribute :hook, :string
44
+
45
+ key_value do
46
+ map :prop, to: :prop
47
+ map :hook, to: :hook
48
+ end
49
+ end
50
+
51
+ class Symbol < Lutaml::Model::Serializable
52
+ attribute :ascii, :string
53
+ attribute :html, :string
54
+ attribute :latex, :string
55
+ attribute :unicode, :string
56
+ attribute :js, JS
57
+
58
+ key_value do
59
+ map :ascii, to: :ascii
60
+ map :html, to: :html
61
+ map :latex, to: :latex
62
+ map :unicode, to: :unicode
63
+ map :js, to: :js
64
+ end
65
+ end
66
+
67
+ class Prefix < Lutaml::Model::Serializable
68
+ attribute :id, :string
69
+ attribute :name, :string
70
+ attribute :symbol, Symbol
71
+ attribute :base, :integer
72
+ attribute :power, :integer
73
+
74
+ key_value do
75
+ map :prefix_id, to: :id
76
+ map :name, to: :name
77
+ map :symbol, to: :symbol
78
+ map :base, to: :base
79
+ map :power, to: :power
80
+ end
81
+ end
82
+
83
+ class Prefixes < Lutaml::Model::Serializable
84
+ attribute :prefixes, Prefix, collection: true
85
+
86
+ key_value do
87
+ map "prefixes", to: :prefixes, child_mappings:
88
+ {
89
+ id: :key,
90
+ name: :name,
91
+ symbol: :symbol,
92
+ base: :base,
93
+ power: :power,
94
+ }
95
+ end
96
+ end
40
97
  end
41
98
 
42
99
  RSpec.describe ChildMapping do
@@ -72,11 +129,52 @@ RSpec.describe ChildMapping do
72
129
  let(:expected_paths) { ["link one", "link two", "link three"] }
73
130
  let(:expected_names) { ["one", "two", "three"] }
74
131
 
132
+ let(:prefixes_hash) do
133
+ {
134
+ "prefixes" => {
135
+ "NISTp10_30" => {
136
+ "name" => "quetta",
137
+ "symbol" => {
138
+ "ascii" => "Q",
139
+ "html" => "Q",
140
+ "latex" => "Q",
141
+ "unicode" => "Q",
142
+ "js" => {
143
+ "prop" => "head",
144
+ "hook" => "async",
145
+ },
146
+ },
147
+ "base" => 10,
148
+ "power" => 30,
149
+ },
150
+ "NISTp10_27" => {
151
+ "name" => "ronna",
152
+ "symbol" => {
153
+ "ascii" => "R",
154
+ "html" => "R",
155
+ "latex" => "R",
156
+ "unicode" => "R",
157
+ "js" => {
158
+ "prop" => "head",
159
+ "hook" => "async",
160
+ },
161
+ },
162
+ "base" => 10,
163
+ "power" => 27,
164
+ },
165
+ },
166
+ }
167
+ end
168
+
75
169
  context "with json" do
76
170
  let(:json) do
77
171
  hash.to_json
78
172
  end
79
173
 
174
+ let(:prefixes_json) do
175
+ prefixes_hash.to_json
176
+ end
177
+
80
178
  describe ".from_json" do
81
179
  it "create model according to json" do
82
180
  instance = mapper.from_json(json)
@@ -86,6 +184,14 @@ RSpec.describe ChildMapping do
86
184
  expect(instance.schemas.map(&:path)).to eq(expected_paths)
87
185
  expect(instance.schemas.map(&:name)).to eq(expected_names)
88
186
  end
187
+
188
+ it "create model according to json with nesting values" do
189
+ instance = ChildMapping::Prefixes.from_json(prefixes_json)
190
+
191
+ expect(instance.prefixes.first.id).to eq("NISTp10_30")
192
+ expect(instance.prefixes.first.symbol.ascii).to eq("Q")
193
+ expect(instance.prefixes.first.symbol.js.hook).to eq("async")
194
+ end
89
195
  end
90
196
 
91
197
  describe ".to_json" do
@@ -98,6 +204,13 @@ RSpec.describe ChildMapping do
98
204
 
99
205
  expect(instance.to_json).to eq(json)
100
206
  end
207
+
208
+ it "converts object to json with nesting values" do
209
+ instance = ChildMapping::Prefixes.from_json(prefixes_json)
210
+ serialized = instance.to_json
211
+
212
+ expect(serialized).to be_equivalent_to(prefixes_json)
213
+ end
101
214
  end
102
215
  end
103
216
 
@@ -106,6 +219,10 @@ RSpec.describe ChildMapping do
106
219
  hash.to_yaml
107
220
  end
108
221
 
222
+ let(:prefixes_yaml) do
223
+ prefixes_hash.to_yaml
224
+ end
225
+
109
226
  describe ".from_yaml" do
110
227
  it "create model according to yaml" do
111
228
  instance = mapper.from_yaml(yaml)
@@ -115,6 +232,14 @@ RSpec.describe ChildMapping do
115
232
  expect(instance.schemas.map(&:path)).to eq(expected_paths)
116
233
  expect(instance.schemas.map(&:name)).to eq(expected_names)
117
234
  end
235
+
236
+ it "create model according to yaml with nesting values" do
237
+ instance = ChildMapping::Prefixes.from_yaml(prefixes_yaml)
238
+
239
+ expect(instance.prefixes.first.id).to eq("NISTp10_30")
240
+ expect(instance.prefixes.first.symbol.ascii).to eq("Q")
241
+ expect(instance.prefixes.first.symbol.js.hook).to eq("async")
242
+ end
118
243
  end
119
244
 
120
245
  describe ".to_yaml" do
@@ -127,6 +252,13 @@ RSpec.describe ChildMapping do
127
252
 
128
253
  expect(instance.to_yaml).to eq(yaml)
129
254
  end
255
+
256
+ it "converts object to yaml with nesting values" do
257
+ instance = ChildMapping::Prefixes.from_yaml(prefixes_yaml)
258
+ serialized = instance.to_yaml
259
+
260
+ expect(YAML.safe_load(serialized)).to eq(YAML.safe_load(prefixes_yaml))
261
+ end
130
262
  end
131
263
  end
132
264
 
@@ -145,6 +277,40 @@ RSpec.describe ChildMapping do
145
277
  TOML
146
278
  end
147
279
 
280
+ let(:prefixes_toml) do
281
+ <<~TOML
282
+ [prefixes.NISTp10_30]
283
+ name = "quetta"
284
+ base = 10
285
+ power = 30
286
+
287
+ [prefixes.NISTp10_30.symbol]
288
+ ascii = "Q"
289
+ html = "Q"
290
+ latex = "Q"
291
+ unicode = "Q"
292
+
293
+ [prefixes.NISTp10_30.symbol.js]
294
+ prop = "head"
295
+ hook = "async"
296
+
297
+ [prefixes.NISTp10_27]
298
+ name = "ronna"
299
+ base = 10
300
+ power = 27
301
+
302
+ [prefixes.NISTp10_27.symbol]
303
+ ascii = "R"
304
+ html = "R"
305
+ latex = "R"
306
+ unicode = "R"
307
+
308
+ [prefixes.NISTp10_27.symbol.js]
309
+ prop = "head"
310
+ hook = "async"
311
+ TOML
312
+ end
313
+
148
314
  describe ".from_toml" do
149
315
  it "create model according to toml" do
150
316
  instance = mapper.from_toml(toml)
@@ -154,6 +320,14 @@ RSpec.describe ChildMapping do
154
320
  expect(instance.schemas.map(&:path)).to eq(expected_paths)
155
321
  expect(instance.schemas.map(&:name)).to eq(expected_names)
156
322
  end
323
+
324
+ it "create model according to toml with nesting values" do
325
+ instance = ChildMapping::Prefixes.from_toml(prefixes_toml)
326
+
327
+ expect(instance.prefixes.first.id).to eq("NISTp10_30")
328
+ expect(instance.prefixes.first.symbol.ascii).to eq("Q")
329
+ expect(instance.prefixes.first.symbol.js.hook).to eq("async")
330
+ end
157
331
  end
158
332
 
159
333
  describe ".to_toml" do
@@ -169,6 +343,14 @@ RSpec.describe ChildMapping do
169
343
 
170
344
  expect(actual.attributes).to eq(expected.attributes)
171
345
  end
346
+
347
+ it "converts object to toml with nesting values" do
348
+ instance = ChildMapping::Prefixes.from_toml(prefixes_toml)
349
+ actual = Lutaml::Model::Config.toml_adapter.parse(instance.to_toml)
350
+ expected = Lutaml::Model::Config.toml_adapter.parse(prefixes_toml)
351
+
352
+ expect(actual.attributes).to eq(expected.attributes)
353
+ end
172
354
  end
173
355
  end
174
356
  end
@@ -86,6 +86,43 @@ RSpec.shared_context "XML namespace models" do
86
86
  prefix: nil
87
87
  end
88
88
  end
89
+
90
+ class Body < Lutaml::Model::Serializable
91
+ attribute :paragraph, :string
92
+
93
+ xml do
94
+ map_element "p", to: :paragraph
95
+ end
96
+ end
97
+
98
+ class Element < Lutaml::Model::Serializable
99
+ attribute :text, :string
100
+ xml do
101
+ root "test-element"
102
+ namespace "http://www.test.com/schemas/test/1.0/", "test"
103
+ map_content to: :text
104
+ end
105
+ end
106
+
107
+ class Front < Lutaml::Model::Serializable
108
+ attribute :test_element, Element
109
+
110
+ xml do
111
+ namespace "http://www.test.com/schemas/test/1.0/", "test"
112
+ map_element "test-element", to: :test_element
113
+ end
114
+ end
115
+
116
+ class Article < Lutaml::Model::Serializable
117
+ attribute :front, Front
118
+ attribute :body, Body
119
+
120
+ xml do
121
+ root "article"
122
+ map_element "front", to: :front, prefix: "test", namespace: "http://www.test.com/schemas/test/1.0/"
123
+ map_element "body", to: :body
124
+ end
125
+ end
89
126
  end
90
127
 
91
128
  RSpec.shared_examples "XML serialization with namespace" do |model_class, xml_string|
@@ -236,6 +273,35 @@ RSpec.shared_examples "an XML namespace parser" do |adapter_class|
236
273
  expect(generated_xml).to be_equivalent_to(xml)
237
274
  end
238
275
  end
276
+
277
+ context "when custom namespace is used" do
278
+ let(:xml_input) do
279
+ <<~XML
280
+ <article xmlns:test="http://www.test.com/schemas/test/1.0/">
281
+ <test:front>
282
+ <test:test-element>Text Here</test:test-element>
283
+ </test:front>
284
+ <body>
285
+ <p>This is a paragraph</p>
286
+ </body>
287
+ </article>
288
+ XML
289
+ end
290
+
291
+ describe "XML serialization" do
292
+ it "correctly deserializes from XML" do
293
+ article = Article.from_xml(xml_input)
294
+ expect(article.body.paragraph).to eq("This is a paragraph")
295
+ end
296
+
297
+ it "round-trips XML" do
298
+ article = Article.from_xml(xml_input)
299
+ output_xml = article.to_xml(pretty: true)
300
+
301
+ expect(output_xml).to be_equivalent_to(xml_input)
302
+ end
303
+ end
304
+ end
239
305
  end
240
306
 
241
307
  RSpec.describe Lutaml::Model::XmlAdapter::NokogiriAdapter do