aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/test/cases/serializers/xml_serialization_test.rb
blob: 7eb48abc3c02e47d5260396b984ecc32bd462a7c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
require 'cases/helper'
require 'models/contact'
require 'active_support/core_ext/object/instance_variables'
require 'ostruct'

class Contact
  extend ActiveModel::Naming
  include ActiveModel::Serializers::Xml

  attr_accessor :address, :friends

  remove_method :attributes if method_defined?(:attributes)

  def attributes
    instance_values.except("address", "friends")
  end
end

module Admin
  class Contact < ::Contact
  end
end

class Customer < Struct.new(:name)
end

class Address
  extend ActiveModel::Naming
  include ActiveModel::Serializers::Xml

  attr_accessor :street, :city, :state, :zip

  def attributes
    instance_values
  end
end

class SerializableContact < Contact
  def serializable_hash(options={})
    super(options.merge(:only => [:name, :age]))
  end
end

class XmlSerializationTest < ActiveModel::TestCase
  def setup
    @contact = Contact.new
    @contact.name = 'aaron stack'
    @contact.age = 25
    @contact.created_at = Time.utc(2006, 8, 1)
    @contact.awesome = false
    customer = Customer.new
    customer.name = "John"
    @contact.preferences = customer
    @contact.address = Address.new
    @contact.address.street = "123 Lane"
    @contact.address.city = "Springfield"
    @contact.address.state = "CA"
    @contact.address.zip = 11111
    @contact.friends = [Contact.new, Contact.new]
  end

  test "should serialize default root" do
    @xml = @contact.to_xml
    assert_match %r{^<contact>},  @xml
    assert_match %r{</contact>$}, @xml
  end

  test "should serialize namespaced root" do
    @xml = Admin::Contact.new(@contact.attributes).to_xml
    assert_match %r{^<contact>},  @xml
    assert_match %r{</contact>$}, @xml
  end

  test "should serialize default root with namespace" do
    @xml = @contact.to_xml :namespace => "http://xml.rubyonrails.org/contact"
    assert_match %r{^<contact xmlns="http://xml.rubyonrails.org/contact">}, @xml
    assert_match %r{</contact>$}, @xml
  end

  test "should serialize custom root" do
    @xml = @contact.to_xml :root => 'xml_contact'
    assert_match %r{^<xml-contact>},  @xml
    assert_match %r{</xml-contact>$}, @xml
  end

  test "should allow undasherized tags" do
    @xml = @contact.to_xml :root => 'xml_contact', :dasherize => false
    assert_match %r{^<xml_contact>},  @xml
    assert_match %r{</xml_contact>$}, @xml
    assert_match %r{<created_at},     @xml
  end

  test "should allow camelized tags" do
    @xml = @contact.to_xml :root => 'xml_contact', :camelize => true
    assert_match %r{^<XmlContact>},  @xml
    assert_match %r{</XmlContact>$}, @xml
    assert_match %r{<CreatedAt},     @xml
  end

  test "should allow lower-camelized tags" do
    @xml = @contact.to_xml :root => 'xml_contact', :camelize => :lower
    assert_match %r{^<xmlContact>},  @xml
    assert_match %r{</xmlContact>$}, @xml
    assert_match %r{<createdAt},     @xml
  end

  test "should use serialiable hash" do
    @contact = SerializableContact.new
    @contact.name = 'aaron stack'
    @contact.age = 25

    @xml = @contact.to_xml
    assert_match %r{<name>aaron stack</name>}, @xml
    assert_match %r{<age type="integer">25</age>}, @xml
    assert_no_match %r{<awesome>}, @xml
  end

  test "should allow skipped types" do
    @xml = @contact.to_xml :skip_types => true
    assert_match %r{<age>25</age>}, @xml
  end

  test "should include yielded additions" do
    @xml = @contact.to_xml do |xml|
      xml.creator "David"
    end
    assert_match %r{<creator>David</creator>}, @xml
  end

  test "should serialize string" do
    assert_match %r{<name>aaron stack</name>}, @contact.to_xml
  end

  test "should serialize nil" do
    assert_match %r{<pseudonyms nil=\"true\"></pseudonyms>}, @contact.to_xml(:methods => :pseudonyms)
  end

  test "should serialize integer" do
    assert_match %r{<age type="integer">25</age>}, @contact.to_xml
  end

  test "should serialize datetime" do
    assert_match %r{<created-at type=\"dateTime\">2006-08-01T00:00:00Z</created-at>}, @contact.to_xml
  end

  test "should serialize boolean" do
    assert_match %r{<awesome type=\"boolean\">false</awesome>}, @contact.to_xml
  end

  test "should serialize array" do
    assert_match %r{<social type=\"array\">\s*<social>twitter</social>\s*<social>github</social>\s*</social>}, @contact.to_xml(:methods => :social)
  end

  test "should serialize hash" do
    assert_match %r{<network>\s*<git type=\"symbol\">github</git>\s*</network>}, @contact.to_xml(:methods => :network)
  end

  test "should serialize yaml" do
    assert_match %r{<preferences type=\"yaml\">--- !ruby/struct:Customer(\s*)\nname: John\n</preferences>}, @contact.to_xml
  end

  test "should call proc on object" do
    proc = Proc.new { |options| options[:builder].tag!('nationality', 'unknown') }
    xml = @contact.to_xml(:procs => [ proc ])
    assert_match %r{<nationality>unknown</nationality>}, xml
  end

  test 'should supply serializable to second proc argument' do
    proc = Proc.new { |options, record| options[:builder].tag!('name-reverse', record.name.reverse) }
    xml = @contact.to_xml(:procs => [ proc ])
    assert_match %r{<name-reverse>kcats noraa</name-reverse>}, xml
  end

  test "should serialize string correctly when type passed" do
    xml = @contact.to_xml :type => 'Contact'
    assert_match %r{<contact type="Contact">}, xml
    assert_match %r{<name>aaron stack</name>}, xml
  end

  test "include option with singular association" do
    xml = @contact.to_xml :include => :address, :indent => 0
    assert xml.include?(@contact.address.to_xml(:indent => 0, :skip_instruct => true))
  end

  test "include option with plural association" do
    xml = @contact.to_xml :include => :friends, :indent => 0
    assert_match %r{<friends type="array">}, xml
    assert_match %r{<friend type="Contact">}, xml
  end

  class FriendList
    def initialize(friends)
      @friends = friends
    end

    def to_ary
      @friends
    end
  end

  test "include option with ary" do
    @contact.friends = FriendList.new(@contact.friends)
    xml = @contact.to_xml :include => :friends, :indent => 0
    assert_match %r{<friends type="array">}, xml
    assert_match %r{<friend type="Contact">}, xml
  end

  test "multiple includes" do
    xml = @contact.to_xml :indent => 0, :skip_instruct => true, :include => [ :address, :friends ]
    assert xml.include?(@contact.address.to_xml(:indent => 0, :skip_instruct => true))
    assert_match %r{<friends type="array">}, xml
    assert_match %r{<friend type="Contact">}, xml
  end

  test "include with options" do
    xml = @contact.to_xml :indent  => 0, :skip_instruct => true, :include => { :address => { :only => :city } }
    assert xml.include?(%(><address><city>Springfield</city></address>))
  end

  test "propagates skip_types option to included associations" do
    xml = @contact.to_xml :include => :friends, :indent => 0, :skip_types => true
    assert_match %r{<friends>}, xml
    assert_match %r{<friend>}, xml
  end
end