require 'spec_helper' require 'tempfile' require 'tmpdir' module XML module Mapping class MXSpecObject include ::XML::Mapping include Comparable root_element_name 'element' numeric_node :attribute, '@attribute' text_node :text, 'text()' array_node :children, 'child', class: String use_mapping :alternate array_node :children, 'children', reader: (proc do |obj, xml| children_elem = xml.elements['children'] obj.children = children_elem ? children_elem.text.split(',') : [] end), writer: (proc do |obj, xml| children_text = obj.children.join(',') if obj.children && !obj.children.empty? xml.add_element('children').text = children_text if children_text end) def <=>(other) return nil unless self.class == other.class [:attribute, :text, :children].each do |p| order = send(p) <=> other.send(p) return order if order != 0 end 0 end def hash [:attribute, :text, :children].hash end end describe '#write_xml' do it 'writes an XML string' do obj = MXSpecObject.new obj.attribute = 123 obj.text = 'element text' obj.children = ['child 1', 'child 2'] expected_xml = obj.save_to_xml xml_string = obj.write_xml expect(xml_string).to be_a(String) expect(xml_string).to be_xml(expected_xml) end it 'accepts an alternate mapping' do obj = MXSpecObject.new obj.attribute = 123 obj.children = ['child 1', 'child 2'] saved_xml = obj.save_to_xml(mapping: :alternate) xml_string = obj.write_xml(mapping: :alternate) expect(xml_string).to be_a(String) expect(xml_string).to be_xml(saved_xml) end end describe '#write_to_file' do before(:each) do @obj = MXSpecObject.new @obj.attribute = 123 @obj.text = 'element text' @obj.children = ['child 1', 'child 2'] @expected = REXML::Document.new(@obj.write_xml) end it 'writes to a file' do Dir.mktmpdir do |tmp| outfile = "#{tmp}/mxspec.xml" @obj.write_to_file(outfile, indent: 4) outxml = File.read(outfile) expect(outxml).to be_xml(@expected) end end it 'pretty-prints to a file' do Dir.mktmpdir do |tmp| outfile = "#{tmp}/mxspec.xml" @obj.write_to_file(outfile, pretty: true) outxml = File.read(outfile) expect(outxml).to be_xml(@expected) end end end describe '#parse_xml' do before(:each) do @xml_string = ' element text child 1 child 2 ' @xml_document = REXML::Document.new(@xml_string) @xml_element = @xml_document.root @expected_element = MXSpecObject.load_from_xml(@xml_element) end it 'parses a String' do obj = MXSpecObject.parse_xml(@xml_string) expect(obj).to eq(@expected_element) end it 'parses a REXML::Document' do obj = MXSpecObject.parse_xml(@xml_document) expect(obj).to eq(@expected_element) end it 'parses a REXML::Element' do obj = MXSpecObject.parse_xml(@xml_element) expect(obj).to eq(@expected_element) end it 'parses an IO' do xml_io = StringIO.new(@xml_string) obj = MXSpecObject.parse_xml(xml_io) expect(obj).to eq(@expected_element) end it 'parses a file' do xml_file = Tempfile.new(%w(parse_xml_spec.xml)) begin xml_file.write(@xml_string) xml_file.rewind obj = MXSpecObject.parse_xml(xml_file) expect(obj).to eq(@expected_element) ensure xml_file.close(true) end end it 'accepts an alternate mapping' do @xml_string = ' element text child 1,child 2 ' @xml_document = REXML::Document.new(@xml_string) @xml_element = @xml_document.root @expected_element = MXSpecObject.load_from_xml(@xml_element, mapping: :alternate) obj = MXSpecObject.parse_xml(@xml_element, mapping: :alternate) expect(obj).to eq(@expected_element) end end end end