google4r-checkout 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGES +40 -0
  2. data/LICENSE +22 -0
  3. data/README +76 -0
  4. data/lib/google4r/checkout.rb +33 -0
  5. data/lib/google4r/checkout/commands.rb +260 -0
  6. data/lib/google4r/checkout/frontend.rb +108 -0
  7. data/lib/google4r/checkout/notifications.rb +549 -0
  8. data/lib/google4r/checkout/shared.rb +541 -0
  9. data/lib/google4r/checkout/xml_generation.rb +313 -0
  10. data/test/integration/checkout_command_test.rb +103 -0
  11. data/test/unit/address_test.rb +131 -0
  12. data/test/unit/area_test.rb +44 -0
  13. data/test/unit/checkout_command_test.rb +116 -0
  14. data/test/unit/checkout_command_xml_generator_test.rb +203 -0
  15. data/test/unit/command_test.rb +115 -0
  16. data/test/unit/flat_rate_shipping_test.rb +114 -0
  17. data/test/unit/frontend_test.rb +63 -0
  18. data/test/unit/item_test.rb +159 -0
  19. data/test/unit/marketing_preferences_test.rb +65 -0
  20. data/test/unit/merchant_code_test.rb +122 -0
  21. data/test/unit/new_order_notification_test.rb +115 -0
  22. data/test/unit/notification_acknowledgement_test.rb +43 -0
  23. data/test/unit/notification_handler_test.rb +93 -0
  24. data/test/unit/order_adjustment_test.rb +119 -0
  25. data/test/unit/order_state_change_notification_test.rb +159 -0
  26. data/test/unit/pickup_shipping_test.rb +70 -0
  27. data/test/unit/postal_area_test.rb +71 -0
  28. data/test/unit/private_data_parser_test.rb +68 -0
  29. data/test/unit/shipping_adjustment_test.rb +100 -0
  30. data/test/unit/shipping_method_test.rb +41 -0
  31. data/test/unit/shopping_cart_test.rb +146 -0
  32. data/test/unit/tax_rule_test.rb +70 -0
  33. data/test/unit/tax_table_test.rb +82 -0
  34. data/test/unit/us_country_area_test.rb +76 -0
  35. data/test/unit/us_state_area_test.rb +70 -0
  36. data/test/unit/us_zip_area_test.rb +66 -0
  37. data/test/unit/world_area_test.rb +48 -0
  38. data/var/cacert.pem +7815 -0
  39. metadata +92 -0
@@ -0,0 +1,313 @@
1
+ #--
2
+ # Project: google4r
3
+ # File: lib/google4r/checkout/xml_generation.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+ # This file contains the classes that allow to persist the object hierarchies
28
+ # that are created with the Google Checkout API to XML.
29
+
30
+ require 'stringio'
31
+ require 'rexml/document'
32
+
33
+ module Google4R #:nodoc:
34
+ module Checkout #:nodoc:
35
+ # Use the CheckoutXmlGenerator to create an XML document from a CheckoutCommand
36
+ # object.
37
+ #
38
+ # Usage:
39
+ #
40
+ # checkout = CheckoutCommand.new
41
+ # # set up the CheckoutCommand
42
+ #
43
+ # generator = CheckoutCommandXmlGenerator.new(checkout)
44
+ # puts generator.generate # => "<xml? version=..."
45
+ # File.new('some.xml', 'w') { |f| f.write generator.generate }
46
+ #--
47
+ # TODO: Refactor the big, monolitic generator into smaller, easier testable ones. One for each major part of the resulting XML document. This will also reduce the overhead in generating other types of XML documents.
48
+ #++
49
+ class CheckoutCommandXmlGenerator
50
+ # Initializes the CheckoutCommandXmlGenerator with the CheckoutCommand it is
51
+ # to conver to XML.
52
+ def initialize(checkout_command)
53
+ @checkout_command = checkout_command
54
+ end
55
+
56
+ # Creates an XML document from the checkout_command passed into the constructor. Returns
57
+ # the resulting XML string.
58
+ def generate
59
+ @document = REXML::Document.new
60
+
61
+ declaration = REXML::XMLDecl.new
62
+ declaration.encoding = 'utf-8'
63
+ @document << declaration
64
+
65
+ self.process_checkout_command(@checkout_command)
66
+
67
+ io = StringIO.new
68
+ @document.write(io, 0) # TODO: Maybe replace 0 by -1 so no spaces are inserted?
69
+ return io.string
70
+ end
71
+
72
+ protected
73
+
74
+ def process_checkout_command(command)
75
+ root = @document.add_element('checkout-shopping-cart', { 'xmlns' => 'http://checkout.google.com/schema/2' })
76
+
77
+ self.process_shopping_shopping_cart(root, command.shopping_cart)
78
+
79
+ # <merchant-checkout-flow-support>
80
+ flow_element = root.add_element('checkout-flow-support').add_element('merchant-checkout-flow-support')
81
+
82
+ # <tax-tables>
83
+ if command.tax_tables then
84
+ self.process_tax_tables(command.tax_tables, flow_element)
85
+ end
86
+
87
+ # <continue-shopping-url>
88
+ if not command.continue_shopping_url.nil? then
89
+ flow_element.add_element('continue-shopping-url').text = command.continue_shopping_url
90
+ end
91
+
92
+ # <edit-cart-url>
93
+ if not command.edit_cart_url.nil? then
94
+ flow_element.add_element('edit-cart-url').text = command.edit_cart_url
95
+ end
96
+
97
+ # <request-buyer-phone-number>
98
+ if not command.request_buyer_phone_number.nil? then
99
+ flow_element.add_element('request-buyer-phone-number').text =
100
+ if command.request_buyer_phone_number then
101
+ "true"
102
+ else
103
+ "false"
104
+ end
105
+ end
106
+
107
+ # <shipping-methods>
108
+ shippings_element = flow_element.add_element('shipping-methods')
109
+ command.shipping_methods.each do |shipping_method|
110
+ self.process_shipping_method(shippings_element, shipping_method)
111
+ end
112
+ end
113
+
114
+ # adds the tax-tables to the parent xml element
115
+ # assumes that the first member of the tax_tables array is the default tax rule table
116
+ # and that all others are alternate tax rules
117
+ def process_tax_tables(tax_tables, parent)
118
+ tax_tables_element = parent.add_element('tax-tables')
119
+
120
+ # assumes that the first tax table is the default
121
+ default_table = tax_tables.first
122
+
123
+ default_table_element = tax_tables_element.add_element('default-tax-table')
124
+ rules_element = default_table_element.add_element('tax-rules')
125
+
126
+ default_table.rules.each do |rule|
127
+ default_rule_element = rules_element.add_element('default-tax-rule')
128
+ default_rule_element.add_element('shipping-taxed').text=rule.shipping_taxed.to_s
129
+ default_rule_element.add_element('rate').text=rule.rate.to_s
130
+ self.process_area(default_rule_element.add_element('tax-area'), rule.area)
131
+ end
132
+
133
+ # populate alternate tax tables
134
+ alt_tables = tax_tables.last(tax_tables.length-1)
135
+ alt_tables_element = tax_tables_element.add_element('alternate-tax-tables')
136
+
137
+ alt_tables.each do |table|
138
+ table_element = alt_tables_element.add_element('alternate-tax-table')
139
+ table_element.add_attribute('name', table.name)
140
+ table_element.add_attribute('standalone', table.standalone.to_s)
141
+
142
+ rules_element = table_element.add_element('alternate-tax-rules')
143
+ table.rules.each do |rule|
144
+ alt_rule_element = rules_element.add_element('alternate-tax-rule')
145
+ alt_rule_element.add_element('rate').text=rule.rate.to_s
146
+
147
+ self.process_area(alt_rule_element.add_element('tax-area'), rule.area)
148
+ end
149
+ end
150
+ end
151
+
152
+
153
+ def process_shopping_shopping_cart(parent, shopping_cart)
154
+ cart_element = parent.add_element('shopping-cart')
155
+
156
+ # add <cart-expiration> tag to the cart if a time has been added to the cart
157
+ if not shopping_cart.expires_at.nil? then
158
+ cart_element.add_element('cart-expiration').add_element('good-until-date').text =
159
+ shopping_cart.expires_at.iso8601
160
+ end
161
+
162
+ # add <merchant-private-data> to the cart if any has been set
163
+ if not shopping_cart.private_data.nil? then
164
+ self.process_hash(cart_element.add_element('merchant-private-data'), shopping_cart.private_data)
165
+ end
166
+
167
+ # process the items in the cart
168
+ items_element = cart_element.add_element('items')
169
+ shopping_cart.items.each do |item|
170
+ self.process_item(items_element, item)
171
+ end
172
+ end
173
+
174
+ # Adds an <item> tag to the tag parent with the appropriate values.
175
+ def process_item(parent, item)
176
+ item_element = parent.add_element('item')
177
+
178
+ item_element.add_element('item-name').text = item.name
179
+ item_element.add_element('item-description').text = item.description
180
+
181
+ item_element.add_element('unit-price', { 'currency' => item.unit_price.currency }).text = item.unit_price.to_s
182
+ item_element.add_element('quantity').text = item.quantity.to_i
183
+
184
+ if not item.id.nil? then
185
+ item_element.add_element('merchant-item-id').text = item.id
186
+ end
187
+
188
+ if not item.private_data.nil? then
189
+ self.process_hash(item_element.add_element('merchant-private-item-data'), item.private_data)
190
+ end
191
+
192
+ # The above was easy; now we need to get the appropriate tax table for this
193
+ # item. The Item class makes sure that the table exists.
194
+ if not item.tax_table.nil? then
195
+ item_element.add_element('tax-table-selector').text = item.tax_table.name
196
+ end
197
+ end
198
+
199
+ # Adds an item for the given shipping method.
200
+ def process_shipping_method(parent, shipping_method)
201
+ if shipping_method.kind_of? PickupShipping then
202
+ process_pickup_shipping(parent, shipping_method)
203
+ elsif shipping_method.kind_of? FlatRateShipping then
204
+ process_flat_rate_shipping(parent, shipping_method)
205
+ else
206
+ raise "Unknown ShippingMethod type of #{shipping_method.inspect}!"
207
+ end
208
+ end
209
+
210
+ def process_flat_rate_shipping(parent, shipping)
211
+ element = parent.add_element('flat-rate-shipping')
212
+ element.add_attribute('name', shipping.name)
213
+ element.add_element('price', { 'currency' => shipping.price.currency }).text = shipping.price.to_s
214
+
215
+ if shipping.excluded_areas.length + shipping.allowed_areas.length > 0 then
216
+ restrictions_tag = element.add_element('shipping-restrictions')
217
+
218
+ if shipping.allowed_areas.length > 0 then
219
+ allowed_tag = restrictions_tag.add_element('allowed-areas')
220
+
221
+ shipping.allowed_areas.each do |area|
222
+ self.process_area(allowed_tag, area)
223
+ end
224
+ end
225
+
226
+ if shipping.excluded_areas.length > 0 then
227
+ excluded_tag = restrictions_tag.add_element('excluded-areas')
228
+
229
+ shipping.excluded_areas.each do |area|
230
+ self.process_area(excluded_tag, area)
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ def process_pickup_shipping(parent, shipping)
237
+ element = parent.add_element('pickup')
238
+ element.add_attribute('name', shipping.name)
239
+ element.add_element('price', { 'currency' => shipping.price.currency }).text = shipping.price.to_s
240
+ end
241
+
242
+ # Adds an appropriate tag for the given Area subclass instance to the parent Element.
243
+ def process_area(parent, area)
244
+ if area.kind_of? UsZipArea then
245
+ parent.add_element('us-zip-area').add_element('zip-pattern').text = area.pattern
246
+ elsif area.kind_of? UsCountryArea then
247
+ parent.add_element('us-country-area', { 'country-area' => area.area })
248
+ elsif area.kind_of? UsStateArea then
249
+ parent.add_element('us-state-area').add_element('state').text = area.state
250
+ elsif area.kind_of? WorldArea then
251
+ parent.add_element('world-area')
252
+ elsif area.kind_of? PostalArea then
253
+ postal_area_element = parent.add_element('postal-area')
254
+ postal_area_element.add_element('country-code').text = area.country_code
255
+ postal_area_element.add_element('postal-code-pattern').text = area.postal_code_pattern
256
+ else
257
+ raise "Area of unknown type: #{area.inspect}."
258
+ end
259
+ end
260
+
261
+ # Converts a Hash into an XML structure. The keys are converted to tag names. If
262
+ # the values are Hashs themselves then process_hash is called upon them. If the
263
+ # values are Arrays then a new element with the key's name will be created.
264
+ #
265
+ # If a value is an Array then this array will be flattened before it is processed.
266
+ # Thus, nested arrays are not allowed.
267
+ #
268
+ # === Example
269
+ #
270
+ # process_hash(parent, { 'foo' => { 'bar' => 'baz' } })
271
+ #
272
+ # # will produce a structure that is equivalent to.
273
+ #
274
+ # <foo>
275
+ # <bar>baz</bar>
276
+ # </foo>
277
+ #
278
+ #
279
+ # process_hash(parent, { 'foo' => [ { 'bar' => 'baz' }, "d'oh", 2 ] })
280
+ #
281
+ # # will produce a structure that is equivalent to.
282
+ #
283
+ # <foo>
284
+ # <bar>baz</bar>
285
+ # </foo>
286
+ # <foo>d&amp;</foo>
287
+ # <foo>2</foo>
288
+ def process_hash(parent, hash)
289
+ hash.each do |key, value|
290
+ if value.kind_of? Array then
291
+ value.flatten.each do |arr_entry|
292
+ if arr_entry.kind_of? Hash then
293
+ self.process_hash(parent.add_element(self.str2tag_name(key.to_s)), arr_entry)
294
+ else
295
+ parent.add_element(self.str2tag_name(key.to_s)).text = arr_entry.to_s
296
+ end
297
+ end
298
+ elsif value.kind_of? Hash then
299
+ process_hash(parent.add_element(self.str2tag_name(key.to_s)), value)
300
+ else
301
+ parent.add_element(self.str2tag_name(key.to_s)).text = value.to_s
302
+ end
303
+ end
304
+ end
305
+
306
+ # Converts a string to a valid XML tag name. Whitespace will be converted into a dash/minus
307
+ # sign, non alphanumeric characters that are neither "-" nor "_" nor ":" will be stripped.
308
+ def str2tag_name(str)
309
+ str.gsub(%r{\s}, '-').gsub(%r{[^a-zA-Z0-9\-\_:]}, '')
310
+ end
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,103 @@
1
+ #--
2
+ # Project: google_checkout4r
3
+ # File: test/checkout/integration/checkout_command.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+
28
+ require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
29
+
30
+ require 'google4r/checkout'
31
+
32
+ require 'test/frontend_configuration'
33
+
34
+ # Integration tests for the CheckoutCommand class.
35
+ #
36
+ # Tests the CheckoutCommand class against the Google Checkout Web Service.
37
+ class Google4R::Checkout::CheckoutCommandIntegrationTest < Test::Unit::TestCase
38
+ include Google4R::Checkout
39
+
40
+ def setup
41
+ @frontend = Frontend.new(FRONTEND_CONFIGURATION)
42
+ @frontend.tax_table_factory = TestTaxTableFactory.new
43
+ @command = @frontend.create_checkout_command
44
+ end
45
+
46
+ def test_sending_to_google_works_with_valid_request
47
+ setup_command(@command)
48
+ result = @command.send_to_google_checkout
49
+ assert_kind_of CheckoutRedirectResponse, result
50
+ end
51
+
52
+ def test_using_invalid_credentials_raise_google_checkout_error
53
+ invalid_patches = [ [ :merchant_id, 'invalid' ], [ :merchant_key, 'invalid' ] ]
54
+
55
+ invalid_patches.each do |patch|
56
+ config = FRONTEND_CONFIGURATION.dup
57
+ config[patch[0]] = patch[1]
58
+ @frontend = Frontend.new(config)
59
+ @frontend.tax_table_factory = TestTaxTableFactory.new
60
+ @command = @frontend.create_checkout_command
61
+
62
+ setup_command(@command)
63
+ assert_raises(GoogleCheckoutError) { @command.send_to_google_checkout }
64
+ end
65
+ end
66
+
67
+ def test_invalid_xml_raises_google_checkout_error
68
+ class << @command
69
+ def to_xml
70
+ ''
71
+ end
72
+ end
73
+
74
+ setup_command(@command)
75
+ assert_raises(GoogleCheckoutError) { @command.send_to_google_checkout }
76
+ end
77
+
78
+ protected
79
+
80
+ # Sets up the given CheckoutCommand so it contains some
81
+ # shipping methods and its cart contains some items.
82
+ def setup_command(command)
83
+ # Add shipping methods.
84
+ command.create_shipping_method(FlatRateShipping) do |shipping|
85
+ shipping.name = 'UPS Ground Shipping'
86
+ shipping.price = Money.new(2000) # USD 20, GPB 20, etc.
87
+ shipping.create_allowed_area(UsCountryArea) do |area|
88
+ area.area = UsCountryArea::ALL
89
+ end
90
+ end
91
+
92
+ # Add items to the cart.
93
+ 1.upto(5) do |i|
94
+ command.shopping_cart.create_item do |item|
95
+ item.name = "Test Item #{i}"
96
+ item.description = "This is a test item (#{i})"
97
+ item.unit_price = Money.new(350)
98
+ item.quantity = i * 3
99
+ item.id = "test-#{i}-123456789"
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,131 @@
1
+ #--
2
+ # Project: google_checkout4r
3
+ # File: test/unit/address_test.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+
28
+ require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
29
+
30
+ require 'google4r/checkout'
31
+
32
+ require 'test/frontend_configuration'
33
+
34
+ # Test for the class Address.
35
+ class Google4R::Checkout::AddressTest < Test::Unit::TestCase
36
+ include Google4R::Checkout
37
+
38
+ def setup
39
+ @data =
40
+ {
41
+ :contact_name => 'John Smith',
42
+ :email => 'johnsmith@example.com',
43
+ :fax => '+01123456789',
44
+ :phone => '+01123456789',
45
+ :address1 => '10 Example Road',
46
+ :address2 => 'Bar',
47
+ :city => 'Sampleville',
48
+ :company_name => 'Company Name',
49
+ :region => 'CA',
50
+ :postal_code => '94141',
51
+ :country_code => 'US',
52
+ }
53
+
54
+ @optional_fields = [ :fax, :phone, :address2, :company_name, :contact_name ]
55
+
56
+ @xml_str = %q{<?xml version="1.0" encoding="UTF-8" ?>
57
+ <root>
58
+ <some-address>
59
+ <contact-name>%s</contact-name>
60
+ <email>%s</email>
61
+ <fax>%s</fax>
62
+ <phone>%s</phone>
63
+ <address1>%s</address1>
64
+ <address2>%s</address2>
65
+ <city>%s</city>
66
+ <company-name>%s</company-name>
67
+ <region>%s</region>
68
+ <postal-code>%s</postal-code>
69
+ <country-code>%s</country-code>
70
+ </some-address>
71
+ </root>}
72
+ end
73
+
74
+ def test_responds_correctly
75
+ @address = Address.new
76
+
77
+ @data.each do |key, value|
78
+ assert_respond_to @address, key, "key == #{key}"
79
+ assert_respond_to @address, "#{key}=".to_sym, "key == #{key}"
80
+ end
81
+ end
82
+
83
+ def test_creating_address_with_full_fields_works
84
+ xml_str = @xml_str %
85
+ [
86
+ @data[:contact_name], @data[:email], @data[:fax], @data[:phone], @data[:address1],
87
+ @data[:address2], @data[:city], @data[:company_name], @data[:region],
88
+ @data[:postal_code], @data[:country_code]
89
+ ]
90
+
91
+ document = REXML::Document.new(xml_str)
92
+
93
+ the_element = document.elements['/root/some-address']
94
+
95
+ address = Address.create_from_element(the_element)
96
+
97
+ @data.each do |key, value|
98
+ assert_equal value, address.send(key)
99
+ end
100
+ end
101
+
102
+ def test_creating_address_works_when_removing_optional_fields
103
+ @optional_fields.power.each do |optional_symbols|
104
+ xml_str = @xml_str %
105
+ [
106
+ @data[:contact_name], @data[:email], @data[:fax], @data[:phone], @data[:address1],
107
+ @data[:address2], @data[:city], @data[:company_name], @data[:region],
108
+ @data[:postal_code], @data[:country_code]
109
+ ]
110
+
111
+ # Remove all optional symbols in this run.
112
+ optional_symbols.each do |symbol|
113
+ xml_str = xml_str.gsub(%r{<#{symbol.to_s.gsub('_', '-')}>.*?</#{symbol.to_s.gsub('_', '-')}>}, '')
114
+ end
115
+
116
+ document = REXML::Document.new(xml_str)
117
+
118
+ the_element = document.elements['/root/some-address']
119
+
120
+ address = Address.create_from_element(the_element)
121
+
122
+ @data.each do |key, value|
123
+ if optional_symbols.include?(key) then
124
+ assert_nil address.send(key)
125
+ else
126
+ assert_equal value, address.send(key)
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end