require "spec_helper" describe Gyoku::Hash do describe ".to_xml" do describe "returns SOAP request compatible XML" do it "for a simple Hash" do expect(to_xml(:some => "user")).to eq("user") end it "for a nested Hash" do expect(to_xml(:some => { :new => "user" })).to eq("user") end context "with key_converter" do it "expect all keys change" do expect(to_xml({:some => { :new => "user" }}, {key_converter: :camelcase})).to eq("user") end it "and key_to_convert option should change only key" do hash = {:some => { :new => "user", :age => 20 }} options = {key_converter: :camelcase, key_to_convert: "some"} result = "user20" expect(to_xml(hash, options)).to eq(result) hash = {:some => { :new => "user", :age => 20 }} options = {key_converter: :camelcase, key_to_convert: "new"} result = "user20" expect(to_xml(hash, options)).to eq(result) end it "with except option, dont convert this key" do hash = {:some => { :new => "user", :age => 20 }} options = {key_converter: :camelcase, except: "some"} result = "user20" expect(to_xml(hash, options)).to eq(result) end end it "for a Hash with multiple keys" do expect(to_xml(:all => "users", :before => "whatever")).to include( "users", "whatever" ) end it "for a Hash containing an Array" do expect(to_xml(:some => ["user", "gorilla"])).to eq("usergorilla") end it "for a Hash containing an Array of Hashes" do expect(to_xml(:some => [{ :new => "user" }, { :old => "gorilla" }])). to eq("usergorilla") end end it "converts Hash key Symbols to lowerCamelCase" do expect(to_xml(:find_or_create => "user")).to eq("user") end it "does not convert Hash key Strings" do expect(to_xml("find_or_create" => "user")).to eq("user") end it "converts DateTime objects to xs:dateTime compliant Strings" do expect(to_xml(:before => DateTime.new(2012, 03, 22, 16, 22, 33))). to eq("2012-03-22T16:22:33+00:00") end it "converts Objects responding to to_datetime to xs:dateTime compliant Strings" do singleton = Object.new def singleton.to_datetime DateTime.new(2012, 03, 22, 16, 22, 33) end expect(to_xml(:before => singleton)).to eq("2012-03-22T16:22:33+00:00") end it "calls to_s on Strings even if they respond to to_datetime" do singleton = "gorilla" def singleton.to_datetime DateTime.new(2012, 03, 22, 16, 22, 33) end expect(to_xml(:name => singleton)).to eq("gorilla") end it "properly serializes nil values" do expect(to_xml(:some => nil)).to eq('') end it "creates self-closing tags for Hash keys ending with a forward slash" do expect(to_xml("self-closing/" => nil)).to eq('') end it "calls to_s on any other Object" do [666, true, false].each do |object| expect(to_xml(:some => object)).to eq("#{object}") end end it "defaults to escape special characters" do result = to_xml(:some => { :nested => "" }, :tag => "") expect(result).to include("<tag />") expect(result).to include("<tag />") end it "does not escape special characters for keys marked with an exclamation mark" do result = to_xml(:some => { :nested! => "" }, :tag! => "") expect(result).to include("") expect(result).to include("") end it "preserves the order of Hash keys and values specified through :order!" do hash = { :find_user => { :name => "Lucy", :id => 666, :order! => [:id, :name] } } result = "666Lucy" expect(to_xml(hash)).to eq(result) hash = { :find_user => { :mname => "in the", :lname => "Sky", :fname => "Lucy", :order! => [:fname, :mname, :lname] } } result = "Lucyin theSky" expect(to_xml(hash)).to eq(result) end it "preserves the order of Hash keys and values specified through 'order!' (as a string key)" do hash = { :find_user => { :name => "Lucy", :id => 666, 'order!' => [:id, :name] } } result = "666Lucy" expect(to_xml(hash)).to eq(result) hash = { :find_user => { :mname => "in the", :lname => "Sky", :fname => "Lucy", 'order!' => [:fname, :mname, :lname] } } result = "Lucyin theSky" expect(to_xml(hash)).to eq(result) end it "uses :order! symbol values for ordering but leaves the string key 'order!' if both are present" do hash = { :find_user => { :name => "Lucy", :id => 666, 'order!' => 'value', :order! => [:id, :name, 'order!'] } } result = "666Lucyvalue" expect(to_xml(hash)).to eq(result) end it "raises if the :order! Array is missing Hash keys" do hash = { :name => "Lucy", :id => 666, :order! => [:name] } expect { to_xml(hash) }.to raise_error(ArgumentError, "Missing elements in :order! [:id]") end it "raises if the :order! Array contains missing Hash keys" do hash = { :by_name => { :first_name => "Lucy", :last_name => "Sky", :order! => [:first_name, :middle_name, :last_name] } } expect { to_xml(hash) }.to raise_error(ArgumentError, "Spurious elements in :order! [:middle_name]") end it "adds attributes to Hash keys specified through :attributes!" do hash = { :find_user => { :person => "Lucy", :attributes! => { :person => { :id => 666 } } } } result = 'Lucy' expect(to_xml(hash)).to eq(result) hash = { :find_user => { :person => "Lucy", :attributes! => { :person => { :id => 666, :city => "Hamburg" } } } } expect(to_xml(hash)).to include('id="666"', 'city="Hamburg"') end it "adds attributes to duplicate Hash keys specified through :attributes!" do hash = { :find_user => { :person => ["Lucy", "Anna"], :attributes! => { :person => { :id => [1, 3] } } } } result = 'LucyAnna' expect(to_xml(hash)).to eq(result) hash = { :find_user => { :person => ["Lucy", "Anna"], :attributes! => { :person => { :active => "true" } } } } result = 'LucyAnna' expect(to_xml(hash)).to eq(result) end it "skips attribute for element without attributes if there are fewer attributes than elements" do hash = { :find_user => { :person => ["Lucy", "Anna", "Beth"], :attributes! => { :person => { :id => [1, 3] } } } } result = 'LucyAnnaBeth' expect(to_xml(hash)).to eq(result) end it "adds attributes to self-closing tags" do hash = { "category/" => "", :attributes! => { "category/" => { :id => 1 } } } expect(to_xml(hash)).to eq('') end it "recognizes @attribute => value along :attributes!" do hash = { "category" => { :content! => "users", :@id => 1 } } expect(to_xml(hash)).to eq('users') end it "recognizes @attribute => value along :attributes! in selfclosed tags" do hash = { "category/" => { :@id => 1 } } expect(to_xml(hash)).to eq('') end it ":@attribute => value takes over :attributes!" do hash = { "category/" => { :@id => 1 }, :attributes! => { "category/" => { 'id' => 2, # will be ignored 'type' => 'admins' } } } # attribute order is undefined expect(['','']).to include to_xml(hash) # with symbols hash = { "category/" => { :@id => 1 }, :attributes! => { "category/" => { :id => 2, # will be ignored :type => 'admins' } } } expect(['','']).to include to_xml(hash) end it "recognizes :content! => value as tag content" do hash = { "category" => { :content! => "users" } } expect(to_xml(hash)).to eq("users") end it "recognizes :content! => value as tag content with value Fixnum" do hash = { "category" => { :content! => 666 } } expect(to_xml(hash)).to eq("666") end it "recognizes :content! => value as tag content with value true" do hash = { "category" => { :content! => true } } expect(to_xml(hash)).to eq("true") end it "recognizes :content! => value as tag content with value false" do hash = { "category" => { :content! => false } } expect(to_xml(hash)).to eq("false") end it "recognizes :content! => value as tag content with value DateTime" do hash = { "before" => { :content! => DateTime.new(2012, 03, 22, 16, 22, 33) } } expect(to_xml(hash)).to eq("2012-03-22T16:22:33+00:00") end it "ignores :content! if self-closing mark present" do hash = { "category/" => { :content! => "users" } } expect(to_xml(hash)).to eq("") end it "recognizes array of attributes" do hash = { "category" => [{:@name => 'one'}, {:@name => 'two'}] } expect(to_xml(hash)).to eq('') # issue #31. hash = { :order! => ['foo', 'bar'], 'foo' => { :@foo => 'foo' }, 'bar' => { :@bar => 'bar', 'baz' => { } }, } expect(to_xml(hash)).to eq('') end it "recognizes array of attributes with content in each" do hash = { "foo" => [{:@name => "bar", :content! => 'gyoku'}, {:@name => "baz", :@some => "attr", :content! => 'rocks!'}] } expect([ 'gyokurocks!', 'gyokurocks!' ]).to include to_xml(hash) end it "recognizes array of attributes but ignores content in each if selfclosing" do hash = { "foo/" => [{:@name => "bar", :content! => 'gyoku'}, {:@name => "baz", :@some => "attr", :content! => 'rocks!'}] } expect([ '', '' ]).to include to_xml(hash) end it "recognizes array of attributes with selfclosing tag" do hash = { "category/" => [{:@name => 'one'}, {:@name => 'two'}] } expect(to_xml(hash)).to eq('') end context "with :element_form_default set to :qualified and a :namespace" do it "adds the given :namespace to every element" do hash = { :first => { "first_name" => "Lucy" }, ":second" => { :":first_name" => "Anna" }, "v2:third" => { "v2:firstName" => "Danie" } } result = to_xml hash, :element_form_default => :qualified, :namespace => :v1 expect(result).to include( "Lucy", "Anna", "Danie" ) end it "adds given :namespace to every element in an array" do hash = { :array => [ :first => "Lucy", :second => "Anna" ]} result = to_xml hash, :element_form_default => :qualified, :namespace => :v1 expect(result).to include("", "Lucy", "Anna") end end it "does not remove special keys from the original Hash" do hash = { :persons => { :first => "Lucy", :second => "Anna", :order! => [:second, :first], :attributes! => { :first => { :first => true } } }, :countries => [:de, :us], :order! => [:countries, :persons], :attributes! => { :countries => { :array => true } } } to_xml(hash) expect(hash).to eq({ :persons => { :first => "Lucy", :second => "Anna", :order! => [:second, :first], :attributes! => { :first => { :first => true } } }, :countries => [:de, :us], :order! => [:countries, :persons], :attributes! => { :countries => { :array => true } } }) end end it "doesn't modify original hash parameter by deleting its attribute keys" do hash = { :person => {:name => "Johnny", :surname => "Bravo", :"@xsi:type" => "People"} } to_xml(hash) expect(hash).to eq({:person=>{:name=>"Johnny", :surname=>"Bravo", :"@xsi:type"=>"People"}}) end def to_xml(hash, options = {}) Gyoku::Hash.to_xml hash, options end end