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