require "spec_helper" require "lutaml/model/xml_adapter/nokogiri_adapter" require "lutaml/model/xml_adapter/ox_adapter" require "lutaml/model/xml_adapter/oga_adapter" require "lutaml/model" RSpec.shared_context "XML namespace models" do class TestModelNoPrefix < Lutaml::Model::Serializable attribute :name, :string xml do root "test" namespace "http://example.com/test", "test" map_element "name", to: :name end end class TestModelWithPrefix < Lutaml::Model::Serializable attribute :name, :string xml do root "test" namespace "http://example.com/test", "test" map_element "name", to: :name end end class SamplePrefixedNamespacedModel < Lutaml::Model::Serializable attribute :id, :string attribute :lang, :string attribute :name, :string, default: -> { "Anonymous" } attribute :age, :integer, default: -> { 18 } xml do root "SamplePrefixedNamespacedModel" namespace "http://example.com/foo", "foo" map_attribute "id", to: :id map_attribute "lang", to: :lang, prefix: "xml", namespace: "http://example.com/xml" map_element "Name", to: :name, prefix: "bar", namespace: "http://example.com/bar" map_element "Age", to: :age, prefix: "baz", namespace: "http://example.com/baz" end end class NamespaceNilPrefixedNamespaced < Lutaml::Model::Serializable attribute :namespace_model, SamplePrefixedNamespacedModel xml do root "NamespaceNil" map_element "SamplePrefixedNamespacedModel", to: :namespace_model, namespace: nil, prefix: nil end end class SampleDefaultNamespacedModel < Lutaml::Model::Serializable attribute :id, :string attribute :lang, :string attribute :name, :string, default: -> { "Anonymous" } attribute :age, :integer, default: -> { 18 } xml do root "SampleDefaultNamespacedModel" namespace "http://example.com/foo" map_attribute "id", to: :id map_attribute "lang", to: :lang, prefix: "xml", namespace: "http://example.com/xml" map_element "Name", to: :name, prefix: "bar", namespace: "http://example.com/bar" map_element "Age", to: :age, prefix: "baz", namespace: "http://example.com/baz" end end class NamespaceNilDefaultNamespaced < Lutaml::Model::Serializable attribute :namespace_model, SampleDefaultNamespacedModel xml do root "NamespaceNil" map_element "SampleDefaultNamespacedModel", to: :namespace_model, namespace: nil, prefix: nil end end end RSpec.shared_examples "XML serialization with namespace" do |model_class, xml_string| it "serializes to XML" do model = model_class.new(name: "Test Name") expect(model.to_xml).to be_equivalent_to(xml_string) end it "deserializes from XML" do model = model_class.from_xml(xml_string) expect(model.name).to eq("Test Name") end end RSpec.shared_examples "an XML namespace parser" do |adapter_class| include_context "XML namespace models" around do |example| old_adapter = Lutaml::Model::Config.xml_adapter Lutaml::Model::Config.xml_adapter = adapter_class example.run ensure Lutaml::Model::Config.xml_adapter = old_adapter end context "with no prefix" do include_examples "XML serialization with namespace", TestModelNoPrefix, 'Test Name' end context "with prefix" do include_examples "XML serialization with namespace", TestModelWithPrefix, 'Test Name' end context "with prefixed namespace" do let(:attributes) { { name: "John Doe", age: 30 } } let(:model) { SamplePrefixedNamespacedModel.new(attributes) } it "serializes to XML" do expected_xml = <<~XML John Doe 30 XML expect(model.to_xml).to be_equivalent_to(expected_xml) end it "deserializes from XML" do xml = <<~XML John Doe 30 XML new_model = SamplePrefixedNamespacedModel.from_xml(xml) expect(new_model.name).to eq("John Doe") expect(new_model.age).to eq(30) end it "round-trips if namespace is set" do xml = <<~XML John Doe 30 XML doc = SamplePrefixedNamespacedModel.from_xml(xml) generated_xml = doc.to_xml expect(generated_xml).to be_equivalent_to(xml) end it "round-trips if namespace is set to nil in parent" do xml = <<~XML John Doe 30 XML doc = NamespaceNilPrefixedNamespaced.from_xml(xml) generated_xml = doc.to_xml expect(generated_xml).to be_equivalent_to(xml) end end context "with default namespace" do let(:attributes) { { name: "Jane Smith", age: 25 } } let(:model) { SampleDefaultNamespacedModel.new(attributes) } it "serializes to XML" do expected_xml = <<~XML Jane Smith 25 XML expect(model.to_xml).to be_equivalent_to(expected_xml) end it "deserializes from XML" do xml = <<~XML Jane Smith 25 XML new_model = SampleDefaultNamespacedModel.from_xml(xml) expect(new_model.name).to eq("Jane Smith") expect(new_model.age).to eq(25) end it "round-trips if namespace is set" do xml = <<~XML Jane Smith 25 XML doc = SampleDefaultNamespacedModel.from_xml(xml) generated_xml = doc.to_xml expect(generated_xml).to be_equivalent_to(xml) end it "round-trips if namespace is set to nil in parent" do xml = <<~XML Jane Smith 25 XML doc = NamespaceNilDefaultNamespaced.from_xml(xml) generated_xml = doc.to_xml expect(generated_xml).to be_equivalent_to(xml) end end end RSpec.describe Lutaml::Model::XmlAdapter::NokogiriAdapter do it_behaves_like "an XML namespace parser", described_class end RSpec.describe Lutaml::Model::XmlAdapter::OxAdapter do it_behaves_like "an XML namespace parser", described_class end RSpec.describe Lutaml::Model::XmlAdapter::OgaAdapter do it_behaves_like "an XML namespace parser", described_class end