google-ads-common 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ChangeLog CHANGED
@@ -1,3 +1,8 @@
1
+ 0.5.1:
2
+ - Now passing response header information as :header field in response.
3
+ - Major performance improvements.
4
+ - Support for proxies.
5
+
1
6
  0.5.0:
2
7
  - Now support Savon 0.9.6.
3
8
  - No longer depend on Soap4r.
@@ -17,7 +17,7 @@
17
17
  # See the License for the specific language governing permissions and
18
18
  # limitations under the License.
19
19
  #
20
- # Generic Api class, to be inherited from and extended by specific APIs.
20
+ # Generic API class, to be inherited from and extended by specific APIs.
21
21
 
22
22
  require 'logger'
23
23
 
@@ -41,24 +41,8 @@ module AdsCommon
41
41
 
42
42
  # Constructor for API.
43
43
  def initialize(provided_config = nil)
44
- load_config(provided_config)
45
- provided_logger = @config.read('library.logger')
46
- self.logger = (provided_logger.nil?) ?
47
- create_default_logger() : provided_logger
48
-
49
- # Check for valid environment.
50
- env_string = @config.read('service.environment')
51
- environment = (env_string.nil?) ? api_config.default_environment :
52
- env_string.to_s.upcase.to_sym
53
- if api_config.environments.include?(environment)
54
- @config.set('service.environment', environment)
55
- else
56
- raise AdsCommon::Errors::Error,
57
- "Unknown or unspecified environment: \"%s\"" % env_string
58
- end
59
-
60
- # Service wrappers.
61
44
  @wrappers = {}
45
+ load_config(provided_config)
62
46
  end
63
47
 
64
48
  # Sets the logger to use.
@@ -87,14 +71,20 @@ module AdsCommon
87
71
 
88
72
  # Check if version exists.
89
73
  if !api_config.versions.include?(version)
90
- raise AdsCommon::Errors::Error, "Unknown version '%s'." % version
74
+ raise AdsCommon::Errors::Error, "Unknown version '%s'" % version
91
75
  end
92
76
 
93
77
  # Check if the current environment supports the requested version.
94
78
  environment = @config.read('service.environment')
79
+
80
+ if !api_config.environments.include?(environment)
81
+ raise AdsCommon::Errors::Error,
82
+ "Unknown or unspecified environment: '%s'" % environment
83
+ end
84
+
95
85
  if !api_config.environment_has_version(environment, version)
96
86
  raise AdsCommon::Errors::Error,
97
- "Environment '%s' does not support version '%s'." %
87
+ "Environment '%s' does not support version '%s'" %
98
88
  [environment, version]
99
89
  end
100
90
 
@@ -168,7 +158,7 @@ module AdsCommon
168
158
  # - a list of SOAP header handlers; one per provided header
169
159
  #
170
160
  def soap_header_handlers(auth_handler, header_list, version, wrapper)
171
- raise NotImplementedError, 'soap_header_handlers not overriden.'
161
+ raise NotImplementedError, 'soap_header_handlers not overridden.'
172
162
  end
173
163
 
174
164
  # Auxiliary method to get an authentication handler. Creates a new one if
@@ -196,8 +186,7 @@ module AdsCommon
196
186
  # - auth handler
197
187
  #
198
188
  def create_auth_handler(environment, version = nil)
199
- auth_method_str = @config.read('authentication.method', 'ClientLogin')
200
- auth_method = auth_method_str.to_s.upcase.to_sym
189
+ auth_method = @config.read('authentication.method', :CLIENTLOGIN)
201
190
  return case auth_method
202
191
  when :CLIENTLOGIN
203
192
  auth_server = api_config.auth_server(environment)
@@ -208,7 +197,7 @@ module AdsCommon
208
197
  AdsCommon::Auth::OAuthHandler.new(config, scope)
209
198
  else
210
199
  raise AdsCommon::Errors::Error,
211
- "Unknown authentication method '%s'." % auth_method_str
200
+ "Unknown authentication method '%s'" % auth_method
212
201
  end
213
202
  end
214
203
 
@@ -256,13 +245,33 @@ module AdsCommon
256
245
  def load_config(provided_config = nil)
257
246
  @config = (provided_config.nil?) ?
258
247
  AdsCommon::Config.new(
259
- File.join(ENV['HOME'], default_config_filename)) :
248
+ File.join(ENV['HOME'], api_config.default_config_filename)) :
260
249
  AdsCommon::Config.new(provided_config)
250
+ init_config()
261
251
  end
262
252
 
263
- # Gets the default config filename.
264
- def default_config_filename()
265
- return api_config.default_config_filename
253
+ # Initializes config with default values and converts existing if required.
254
+ def init_config()
255
+ # Set up logger.
256
+ provided_logger = @config.read('library.logger')
257
+ self.logger = (provided_logger.nil?) ?
258
+ create_default_logger() : provided_logger
259
+
260
+ # Validating most important parameters.
261
+ ['service.environment', 'authentication.method'].each do |parameter|
262
+ symbolize_config_value(parameter)
263
+ end
264
+ end
265
+
266
+ # Converts value of a config key to uppercase symbol.
267
+ def symbolize_config_value(key)
268
+ value_str = @config.read(key).to_s
269
+ if !value_str.nil? and !value_str.empty?
270
+ value = value_str.upcase.to_sym
271
+ @config.set(key, value)
272
+ else
273
+ @logger.warn("Empty value for required parameter: '%s'" % key)
274
+ end
266
275
  end
267
276
 
268
277
  # Converts log level string (from config) to Logger value.
@@ -26,7 +26,7 @@ module AdsCommon
26
26
  # Contains helper methods for loading and managing the available services.
27
27
  # This module is meant to be imported into API-specific modules.
28
28
  module ApiConfig
29
- ADS_COMMON_VERSION = '0.5.0'
29
+ ADS_COMMON_VERSION = '0.5.1'
30
30
 
31
31
  # Get the available API versions.
32
32
  #
@@ -144,6 +144,8 @@ module AdsCommon
144
144
  validate_credentials(credentials)
145
145
  if @consumer.nil?
146
146
  oauth_config = OAUTH_CONFIG.merge({:scope => @scope})
147
+ proxy = @config.read('connection.proxy')
148
+ oauth_config[:proxy] = proxy if !proxy.nil?
147
149
  @consumer = OAuth::Consumer.new(credentials[:oauth_consumer_key],
148
150
  credentials[:oauth_consumer_secret], oauth_config)
149
151
  end
@@ -198,9 +200,9 @@ module AdsCommon
198
200
  callback = credentials[:oauth_callback] || DEFAULT_CALLBACK
199
201
  begin
200
202
  if @request_token.nil?
201
- @request_token = @consumer.get_request_token(
202
- {:oauth_callback => callback}, {:scope => @scope})
203
- raise_oauth_verification_error(@request_token, callback)
203
+ @request_token = credentials[:oauth_request_token] ||
204
+ @consumer.get_request_token({:oauth_callback => callback},
205
+ {:scope => @scope})
204
206
  end
205
207
  verification_code = credentials[:oauth_verification_code]
206
208
  if verification_code.nil? || verification_code.empty?
@@ -236,7 +238,9 @@ module AdsCommon
236
238
  #
237
239
  def raise_oauth_verification_error(request_token, callback)
238
240
  oauth_url = request_token.authorize_url({:oauth_callback => callback})
239
- raise AdsCommon::Errors::OAuthVerificationRequired, oauth_url
241
+ error = AdsCommon::Errors::OAuthVerificationRequired.new(
242
+ oauth_url, request_token)
243
+ raise error
240
244
  end
241
245
 
242
246
  # Extracts key-value pairs from OAuth server response.
@@ -61,6 +61,7 @@ module AdsCommon
61
61
  config.log_level = :debug
62
62
  end
63
63
  HTTPI.logger = @logger
64
+ HTTPI.log_level = :debug
64
65
  end
65
66
 
66
67
  #
@@ -34,6 +34,8 @@ module AdsCommon
34
34
  #
35
35
  # <%= @generator_stamp %>
36
36
 
37
+ require '<%= @api_name.snakecase %>/errors'
38
+
37
39
  <%= @modules_open_string %>
38
40
 
39
41
  class <%= @service_name %>Registry
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Authors:: api.dklimkin@gmail.com (Danial Klimkin)
4
4
  #
5
- # Copyright:: Copyright 2010, Google Inc. All Rights Reserved.
5
+ # Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
6
6
  #
7
7
  # License:: Licensed under the Apache License, Version 2.0 (the "License");
8
8
  # you may not use this file except in compliance with the License.
@@ -54,10 +54,10 @@ module AdsCommon
54
54
  if property_path
55
55
  last_node = @config
56
56
  last_name = property_path.split('.').inject(nil) do |last_name, section|
57
- last_node = last_node[last_name.to_sym] ||= {} unless last_name.nil?
58
- section
57
+ last_node = last_node[last_name] ||= {} unless last_name.nil?
58
+ section.to_sym
59
59
  end
60
- last_node[last_name.to_sym] = value
60
+ last_node[last_name] = value
61
61
  end
62
62
  return nil
63
63
  end
@@ -65,6 +65,21 @@ module AdsCommon
65
65
  # Writes an entire set of properties.
66
66
  def set_all(properties)
67
67
  @config = process_hash_keys(properties)
68
+ return nil
69
+ end
70
+
71
+ # Reads a configuration file into instance variable as a Ruby structure with
72
+ # the complete set of keys and values.
73
+ #
74
+ # Args:
75
+ # - filename: config file to be read (*String*)
76
+ #
77
+ # Raises:
78
+ # - <b>Errno::ENOENT</b> if the file does not exist.
79
+ #
80
+ def load(filename)
81
+ @config = YAML::load_file(filename)
82
+ return nil
68
83
  end
69
84
 
70
85
  private
@@ -89,19 +104,5 @@ module AdsCommon
89
104
  (node.is_a?(Hash) and node.include?(key)) ? node[key] : nil
90
105
  end
91
106
  end
92
-
93
- # Reads a configuration file into instance variable as a Ruby structure with
94
- # the complete set of keys and values.
95
- #
96
- # Args:
97
- # - filename: config file to be read (*String*)
98
- #
99
- # Raises:
100
- # - <b>Errno::ENOENT</b> if the file does not exist.
101
- #
102
- def load(filename)
103
- @config = YAML::load_file(filename)
104
- return nil
105
- end
106
107
  end
107
108
  end
@@ -42,9 +42,10 @@ module AdsCommon
42
42
  # Raised when OAuth access token is required.
43
43
  class OAuthVerificationRequired < AuthError
44
44
  attr_reader :oauth_url
45
- def initialize(oauth_url)
45
+ attr_reader :request_token
46
+ def initialize(oauth_url, request_token)
46
47
  super()
47
- @oauth_url = oauth_url
48
+ @oauth_url, @request_token = oauth_url, request_token
48
49
  end
49
50
  end
50
51
 
@@ -30,7 +30,7 @@ module AdsCommon
30
30
  # Performs a get on a URL, using all of the connection options in the
31
31
  # client library, returning a HTTPI::Response.
32
32
  def self.get_response(url, config = nil, headers = nil)
33
- request = prepare_request(config, url, headers)
33
+ request = prepare_request(url, config, headers)
34
34
  response = HTTPI.get(request)
35
35
  return response
36
36
  end
@@ -44,7 +44,7 @@ module AdsCommon
44
44
  # Performs a post on a URL, using all of the connection options in the
45
45
  # client library, returning a HTTPI::Response.
46
46
  def self.post_response(url, data, config = nil, headers = nil)
47
- request = prepare_request(config, url, headers, data)
47
+ request = prepare_request(url, config, headers, data)
48
48
  response = HTTPI.post(request)
49
49
  return response
50
50
  end
@@ -59,17 +59,22 @@ module AdsCommon
59
59
 
60
60
  # Returns a suitably configured request object for a given URL and options.
61
61
  # Defaulting to stricter :peer validation.
62
- def self.prepare_request(config, url, headers = nil, data = nil)
62
+ def self.prepare_request(url, config = nil, headers = nil, data = nil)
63
63
  request = HTTPI::Request.new(url)
64
- proxy = config.read('connection.proxy', nil)
65
- request.proxy = proxy if proxy
66
- strict_ssl = config.nil? or
67
- !(config.read('connection.strict_ssl_verification') == 'false')
68
- request.auth.ssl.verify_mode = strict_ssl ? :peer : :none
69
64
  request.headers = headers if headers
70
65
  request.body = data if data
71
- logger = config.read('library.logger')
72
- HTTPI.logger = logger if logger
66
+ if config
67
+ proxy = config.read('connection.proxy', nil)
68
+ request.proxy = proxy if !proxy.nil?
69
+ strict_ssl =
70
+ !(config.read('connection.strict_ssl_verification') == 'false')
71
+ request.auth.ssl.verify_mode = strict_ssl ? :peer : :none
72
+ logger = config.read('library.logger')
73
+ if logger
74
+ HTTPI.logger = logger
75
+ HTTPI.log_level = :debug
76
+ end
77
+ end
73
78
  return request
74
79
  end
75
80
  end
@@ -19,6 +19,8 @@
19
19
  #
20
20
  # Base class for handlers of SOAP headers.
21
21
 
22
+ require 'savon'
23
+
22
24
  module AdsCommon
23
25
  module SavonHeaders
24
26
  class BaseHeaderHandler
@@ -62,8 +64,12 @@ module AdsCommon
62
64
  soap.body = args if args
63
65
  # Sets the default namespace for the body.
64
66
  soap.input[2] = {:xmlns => @namespace}
67
+ # Sets User-Agent in the HTTP header.
68
+ request.headers['User-Agent'] = generate_user_agent_string()
65
69
  end
66
70
 
71
+ private
72
+
67
73
  # Adds namespace to the given string.
68
74
  #
69
75
  # Args:
@@ -75,6 +81,17 @@ module AdsCommon
75
81
  def prepend_namespace(str)
76
82
  return "%s:%s" % [DEFAULT_NAMESPACE, str]
77
83
  end
84
+
85
+ # Generates User-Agent text for HTTP request.
86
+ def generate_user_agent_string()
87
+ credentials = @credential_handler.credentials
88
+ app_name = credentials[:user_agent]
89
+ # We don't know the library version here. A breaking change needs to be
90
+ # introduced. This is scheduled for 0.6.0, using Common version for now.
91
+ lib_version = '0.5.1'
92
+ soap_user_agent = "Common-Ruby-%s; %s" % [lib_version, app_name]
93
+ return "Savon/%s (%s)" % [Savon::Version, soap_user_agent]
94
+ end
78
95
  end
79
96
  end
80
97
  end
@@ -19,6 +19,7 @@
19
19
  #
20
20
  # Base class for all generated API services based on Savon backend.
21
21
 
22
+ require 'httpi'
22
23
  require 'savon'
23
24
 
24
25
  module AdsCommon
@@ -26,6 +27,9 @@ module AdsCommon
26
27
  # Default namespace name.
27
28
  DEFAULT_NAMESPACE = 'wsdl'
28
29
 
30
+ # HTTP read timeout in seconds.
31
+ HTTP_READ_TIMEOUT = 15 * 60
32
+
29
33
  attr_accessor :headerhandler
30
34
  attr_reader :api
31
35
  attr_reader :version
@@ -34,28 +38,45 @@ module AdsCommon
34
38
  # Creates a new service.
35
39
  def initialize(api, endpoint, namespace, version)
36
40
  if self.class() == AdsCommon::SavonService
37
- raise NoMethodError, "Tried to instantiate an abstract class"
41
+ raise NoMethodError, 'Tried to instantiate an abstract class'
38
42
  end
39
- @api = api
40
- @version = version
41
- @namespace = namespace
43
+ @api, @version, @namespace = api, version, namespace
42
44
  @headerhandler = []
43
- @client = Savon::Client.new do |wsdl|
44
- wsdl.namespace = namespace
45
- wsdl.endpoint = endpoint
46
- end
45
+ @client = create_savon_client(endpoint, namespace)
47
46
  end
48
47
 
49
48
  private
50
49
 
51
- # Returns ServiceRegistry for the current service. Has to be overriden.
50
+ # Sets the logger in Savon-specific way. Also sets it for HTTPI used by it.
51
+ def self.logger=(logger)
52
+ Savon.configure do |config|
53
+ config.log_level = :debug
54
+ config.logger = logger
55
+ end
56
+ HTTPI.logger = logger
57
+ HTTPI.log_level = :debug
58
+ end
59
+
60
+ # Returns ServiceRegistry for the current service. Has to be overridden.
52
61
  def get_service_registry()
53
- raise NoMethodError, "This methods needs to be overriden"
62
+ raise NoMethodError, 'This method needs to be overridden'
54
63
  end
55
64
 
56
- # Returns Module for the current service. Has to be overriden.
65
+ # Returns Module for the current service. Has to be overridden.
57
66
  def get_module()
58
- raise NoMethodError, "This methods needs to be overriden"
67
+ raise NoMethodError, 'This method needs to be overridden'
68
+ end
69
+
70
+ # Creates and sets up Savon client.
71
+ def create_savon_client(endpoint, namespace)
72
+ proxy = @api.config.read('connection.proxy')
73
+ client = Savon::Client.new do |wsdl, http|
74
+ wsdl.endpoint = endpoint
75
+ wsdl.namespace = namespace
76
+ http.proxy = proxy if !proxy.nil?
77
+ http.read_timeout = HTTP_READ_TIMEOUT
78
+ end
79
+ return client
59
80
  end
60
81
 
61
82
  # Executes SOAP action specified as a string with given arguments.
@@ -131,7 +152,7 @@ module AdsCommon
131
152
  xsi_field_type = get_full_type_signature(xsi_type)
132
153
  if xsi_field_type.nil?
133
154
  raise AdsCommon::Errors::ApiException.new(
134
- "Incorrect xsi:type specified: %s" % [xsi_type])
155
+ "Incorrect xsi:type specified: '%s'" % [xsi_type])
135
156
  else
136
157
  # TODO: make sure xsi_type is derived from field_type.
137
158
  field_type = xsi_field_type
@@ -167,7 +188,7 @@ module AdsCommon
167
188
  [subtype_name, subtype]
168
189
  end
169
190
  # In case of non-default namespace, the children should be in
170
- # overriden namespace but the node has to be in the default.
191
+ # overridden namespace but the node has to be in the default.
171
192
  # We also have to fix order! list if we alter the key name.
172
193
  new_key = if (subtype and subtype[:ns])
173
194
  prefixed_key = prefix_key(k)
@@ -196,7 +217,12 @@ module AdsCommon
196
217
  def add_attribute(node, key, name, value)
197
218
  node[:attributes!] ||= {}
198
219
  node[:attributes!][key] ||= {}
199
- node[:attributes!][key][name] = value
220
+ if node[:attributes!][key].include?(name)
221
+ node[:attributes!][key][name] = arrayize(node[:attributes!][key][name])
222
+ node[:attributes!][key][name] << value
223
+ else
224
+ node[:attributes!][key][name] = value
225
+ end
200
226
  end
201
227
 
202
228
  # Prefixes default namespace.
@@ -253,7 +279,24 @@ module AdsCommon
253
279
  action = method[:output][:name].to_sym
254
280
  result = response.to_hash
255
281
  result = result[action] if result.include?(action)
256
- return normalize_output(result, method)
282
+ result = normalize_output(result, method)
283
+ result[:header] = extract_header_data(response) if result.kind_of?(Hash)
284
+ return result
285
+ end
286
+
287
+ # Extracts misc data from response header.
288
+ def extract_header_data(response)
289
+ header_type = get_full_type_signature(:SoapResponseHeader)
290
+ headers = response.header[:response_header].dup
291
+ result = headers.inject({}) do |result, (key, v)|
292
+ # Attributes start with '@' and are not included in type definition.
293
+ if !(key.to_s.start_with?('@'))
294
+ normalize_output_field(headers, header_type[:fields], key)
295
+ result[key] = headers[key]
296
+ end
297
+ result
298
+ end
299
+ return result
257
300
  end
258
301
 
259
302
  # Normalizes output starting with root node "rval".
@@ -271,26 +314,28 @@ module AdsCommon
271
314
  def normalize_output_field(output_data, fields_list, field_name)
272
315
  return nil if output_data.nil?
273
316
  field_definition = get_field_by_name(fields_list, field_name)
317
+ if field_definition.nil?
318
+ @api.logger.warn("Can not determine type for field: %s" % field_name)
319
+ return output_data
320
+ end
321
+
274
322
  field_sym = field_name.to_sym
275
- output_data[field_sym] = normalize_type(output_data[field_sym],
276
- field_definition)
323
+ field_data = normalize_type(output_data[field_sym], field_definition)
324
+ output_data[field_sym] = field_data if field_data
277
325
 
278
326
  sub_type = get_full_type_signature(field_definition[:type])
279
327
  if sub_type and sub_type[:fields]
280
328
  # go recursive
281
329
  sub_type[:fields].each do |sub_type_field|
282
- if output_data[field_sym].is_a?(Array)
283
- items_list = output_data[field_sym]
284
- output_data[field_sym] = []
285
- items_list.each do |item|
286
- output_data[field_sym] <<
287
- normalize_output_field(item, sub_type_field,
288
- sub_type_field[:name])
330
+ field_data = output_data[field_sym]
331
+ if field_data.is_a?(Array)
332
+ field_data.each do |item|
333
+ normalize_output_field(item, sub_type_field,
334
+ sub_type_field[:name])
289
335
  end
290
336
  else
291
- output_data[field_sym] =
292
- normalize_output_field(output_data[field_sym], sub_type_field,
293
- sub_type_field[:name])
337
+ normalize_output_field(field_data, sub_type_field,
338
+ sub_type_field[:name])
294
339
  end
295
340
  end
296
341
  end
@@ -356,7 +401,11 @@ module AdsCommon
356
401
  parent_type = get_service_registry.get_type_signature(data_type[:base])
357
402
  result += implode_parent(parent_type)
358
403
  end
359
- result += data_type[:fields]
404
+ data_type[:fields].each do |field|
405
+ # If the parent type includes a field with the same name, overwrite it.
406
+ result.reject! {|parent_field| parent_field[:name].eql?(field[:name])}
407
+ result << field
408
+ end
360
409
  return result
361
410
  end
362
411
 
@@ -22,12 +22,25 @@
22
22
  require 'rubygems'
23
23
  require 'test/unit'
24
24
 
25
+ require 'ads_common/config'
25
26
  require 'ads_common/savon_service'
26
27
 
28
+ # AdsCommon::Api is abstract, defining a stub class for the test.
29
+ class StubApi
30
+ attr_accessor :config
31
+ def initialize()
32
+ @config = AdsCommon::Config.new
33
+ end
34
+ def self.get_instance()
35
+ @api ||= StubApi.new
36
+ return @api
37
+ end
38
+ end
39
+
27
40
  # SavonService is abstract, defining a child class for the test.
28
- class SomeService < AdsCommon::SavonService
41
+ class StubService < AdsCommon::SavonService
29
42
  def initialize(namespace, endpoint, version)
30
- super(nil, namespace, endpoint, version)
43
+ super(StubApi.get_instance(), namespace, endpoint, version)
31
44
  end
32
45
  def private_get_service_registry()
33
46
  return get_service_registry
@@ -47,6 +60,9 @@ class SomeService < AdsCommon::SavonService
47
60
  def private_deep_copy(object)
48
61
  return deep_copy(object)
49
62
  end
63
+ def private_add_attribute(node, key, name, value)
64
+ return add_attribute(node, key, name, value)
65
+ end
50
66
  end
51
67
 
52
68
  class TestSavonService < Test::Unit::TestCase
@@ -56,7 +72,7 @@ class TestSavonService < Test::Unit::TestCase
56
72
 
57
73
  # Initialize tests.
58
74
  def setup
59
- @some_service = SomeService.new(TEST_NAMESPACE, TEST_ENDPOINT, TEST_VERSION)
75
+ @stub_service = StubService.new(TEST_NAMESPACE, TEST_ENDPOINT, TEST_VERSION)
60
76
  end
61
77
 
62
78
  def test_initialize_abstract
@@ -65,35 +81,35 @@ class TestSavonService < Test::Unit::TestCase
65
81
  TEST_VERSION)
66
82
  end
67
83
  assert_nothing_raised do
68
- SomeService.new(TEST_NAMESPACE, TEST_ENDPOINT, TEST_VERSION)
84
+ StubService.new(TEST_NAMESPACE, TEST_ENDPOINT, TEST_VERSION)
69
85
  end
70
86
  end
71
87
 
72
88
  def test_get_service_registry_abstract
73
- assert_raises(NoMethodError) { @some_service.private_get_service_registry }
89
+ assert_raises(NoMethodError) { @stub_service.private_get_service_registry }
74
90
  end
75
91
 
76
92
  def test_get_module_abstract
77
- assert_raises(NoMethodError) { @some_service.private_get_module }
93
+ assert_raises(NoMethodError) { @stub_service.private_get_module }
78
94
  end
79
95
 
80
96
  def test_arrayize_empty
81
- result1 = @some_service.private_arrayize(nil)
97
+ result1 = @stub_service.private_arrayize(nil)
82
98
  assert_instance_of(Array, result1, 'returned object is not an Array')
83
99
  assert_equal(0, result1.size, 'array is not empty')
84
100
 
85
- result2 = @some_service.private_arrayize([])
101
+ result2 = @stub_service.private_arrayize([])
86
102
  assert_instance_of(Array, result2, 'returned object is not an Array')
87
103
  assert_equal(0, result2.size, 'array is not empty')
88
104
  end
89
105
 
90
106
  def test_arrayize_on_array
91
- result1 = @some_service.private_arrayize([nil])
107
+ result1 = @stub_service.private_arrayize([nil])
92
108
  assert_instance_of(Array, result1, 'returned object is not an Array')
93
109
  assert_equal(1, result1.size, 'array changed size')
94
110
  assert_equal(nil, result1[0], 'array changed data')
95
111
 
96
- result2 = @some_service.private_arrayize(['a', 'b'])
112
+ result2 = @stub_service.private_arrayize(['a', 'b'])
97
113
  assert_instance_of(Array, result2, 'returned object is not an Array')
98
114
  assert_equal(2, result2.size, 'array changed size')
99
115
  assert_equal('a', result2[0], 'array changed data')
@@ -101,119 +117,124 @@ class TestSavonService < Test::Unit::TestCase
101
117
  end
102
118
 
103
119
  def test_normalize_type_int
104
- result1 = @some_service.private_normalize_type(5, {:type => 'int'})
120
+ result1 = @stub_service.private_normalize_type(5, {:type => 'int'})
105
121
  assert_kind_of(Integer, result1)
106
122
  assert_equal(5, result1, 'bad conversion')
107
123
 
108
- result2 = @some_service.private_normalize_type(2147483648, {:type => 'int'})
124
+ result2 = @stub_service.private_normalize_type(2147483648, {:type => 'int'})
109
125
  assert_kind_of(Integer, result2)
110
126
  assert_equal(2147483648, result2, 'bad conversion')
111
127
  end
112
128
 
113
129
  def test_normalize_type_string
114
- result1 = @some_service.private_normalize_type('foobar',
130
+ result1 = @stub_service.private_normalize_type('foobar',
115
131
  {:type => 'string'})
116
132
  assert_kind_of(String, result1)
117
133
  assert_equal('foobar', result1, 'bad conversion')
118
134
 
119
- result2 = @some_service.private_normalize_type('', {:type => 'string'})
135
+ result2 = @stub_service.private_normalize_type('', {:type => 'string'})
120
136
  assert_kind_of(String, result2)
121
137
  assert_equal('', result2, 'bad conversion')
122
138
  end
123
139
 
124
140
  def test_normalize_type_long
125
- result1 = @some_service.private_normalize_type(2147483648,
141
+ result1 = @stub_service.private_normalize_type(2147483648,
126
142
  {:type => 'long'})
127
143
  assert_kind_of(Integer, result1)
128
144
  assert_equal(2147483648, result1, 'bad conversion')
129
145
 
130
- result2 = @some_service.private_normalize_type(-1, {:type => 'long'})
146
+ result2 = @stub_service.private_normalize_type(-1, {:type => 'long'})
131
147
  assert_kind_of(Integer, result2)
132
148
  assert_equal(-1, result2, 'bad conversion')
133
149
  end
134
150
 
135
151
  def test_normalize_type_boolean
136
- result1 = @some_service.private_normalize_type(true, {:type => 'boolean'})
152
+ result1 = @stub_service.private_normalize_type(true, {:type => 'boolean'})
137
153
  assert_kind_of(TrueClass, result1)
138
154
 
139
- result2 = @some_service.private_normalize_type(false, {:type => 'boolean'})
155
+ result2 = @stub_service.private_normalize_type(false, {:type => 'boolean'})
140
156
  assert_kind_of(FalseClass, result2)
141
157
 
142
- result3 = @some_service.private_normalize_type('true', {:type => 'boolean'})
158
+ result3 = @stub_service.private_normalize_type('true', {:type => 'boolean'})
143
159
  assert_kind_of(TrueClass, result3)
144
160
 
145
- result4 = @some_service.private_normalize_type('false',
161
+ result4 = @stub_service.private_normalize_type('false',
146
162
  {:type => 'boolean'})
147
163
  assert_kind_of(FalseClass, result4)
148
164
 
149
- result5 = @some_service.private_normalize_type('True',
165
+ result5 = @stub_service.private_normalize_type('True',
150
166
  {:type => 'boolean'})
151
167
  assert_kind_of(TrueClass, result3)
152
168
 
153
- result6 = @some_service.private_normalize_type('False',
169
+ result6 = @stub_service.private_normalize_type('False',
154
170
  {:type => 'boolean'})
155
171
  assert_kind_of(FalseClass, result4)
156
172
  end
157
173
 
158
174
  def test_normalize_type_object
159
- result1 = @some_service.private_normalize_type({:a => 'b'},
160
- {:type => 'SomeClass'})
175
+ result1 = @stub_service.private_normalize_type({:a => 'b'},
176
+ {:type => 'StubClass'})
161
177
  assert_equal('b', result1[:a], 'object corrupted')
162
178
 
163
- result2 = @some_service.private_normalize_type(@some_service,
179
+ result2 = @stub_service.private_normalize_type(@stub_service,
164
180
  {:type => 'SavonService'})
165
- assert_equal(@some_service.hash, result2.hash, 'object corrupted')
181
+ assert_equal(@stub_service.hash, result2.hash, 'object corrupted')
166
182
  end
167
183
 
168
184
  def test_normalize_type_double
169
- result1 = @some_service.send(:private_normalize_type, 3.14,
185
+ result1 = @stub_service.send(:private_normalize_type, 3.14,
170
186
  {:type => 'double'})
171
187
  assert_kind_of(Float, result1)
172
188
  assert_equal(3.14, result1, 'bad conversion')
173
189
 
174
- result2 = @some_service.send(:private_normalize_type, '-3.14',
190
+ result2 = @stub_service.send(:private_normalize_type, '-3.14',
175
191
  {:type => 'double'})
176
192
  assert_kind_of(Float, result2)
177
193
  assert_equal(-3.14, result2, 'bad conversion')
178
194
 
179
- result3 = @some_service.send(:private_normalize_type, '42',
195
+ result3 = @stub_service.send(:private_normalize_type, '42',
180
196
  {:type => 'double'})
181
197
  assert_kind_of(Float, result3)
182
198
  assert_equal(42.0, result3, 'bad conversion')
183
199
  end
184
200
 
185
201
  def test_normalize_type_single_array_item
186
- result1 = @some_service.private_normalize_type('42',
202
+ result1 = @stub_service.private_normalize_type('42',
187
203
  {:type => 'double', :min_occurs => '0', :max_occurs => 1})
188
204
  assert_kind_of(Float, result1)
189
- assert_equal(42.0, result1, 'Float expected for max_occurs 1')
205
+ assert_equal(42.0, result1, 'Float is expected for max_occurs 1')
190
206
 
191
- result2 = @some_service.private_normalize_type('42',
192
- {:type => 'double', :min_occurs => '0', :max_occurs => nil})
207
+ result2 = @stub_service.private_normalize_type('42',
208
+ {:type => 'double', :min_occurs => '0', :max_occurs => :unbounded})
193
209
  assert_instance_of(Array, result2)
194
- assert_equal(42.0, result2[0], 'Array is expected for undefined max_occurs')
210
+ assert_equal(42.0, result2[0], 'Array is expected for unbounded max_occurs')
195
211
 
196
- result3 = @some_service.private_normalize_type('42',
212
+ result3 = @stub_service.private_normalize_type('42',
197
213
  {:type => 'double', :min_occurs => '0', :max_occurs => 2})
198
214
  assert_instance_of(Array, result3)
199
215
  assert_equal(42.0, result3[0], 'Array is expected for max_occurs > 1')
216
+
217
+ result4 = @stub_service.private_normalize_type('42',
218
+ {:type => 'double', :min_occurs => '0', :max_occurs => nil})
219
+ assert_instance_of(Float, result4)
220
+ assert_equal(42.0, result4, 'Float is expected for nil max_occurs')
200
221
  end
201
222
 
202
223
  def test_deep_copy_simple
203
- result1 = @some_service.private_deep_copy(42)
224
+ result1 = @stub_service.private_deep_copy(42)
204
225
  assert_equal(42, result1)
205
226
 
206
- result2 = @some_service.private_deep_copy('Hello World')
227
+ result2 = @stub_service.private_deep_copy('Hello World')
207
228
  assert_equal('Hello World', result2)
208
229
 
209
- result3 = @some_service.private_deep_copy(nil)
230
+ result3 = @stub_service.private_deep_copy(nil)
210
231
  assert_nil(result3)
211
232
 
212
- result4 = @some_service.private_deep_copy([])
233
+ result4 = @stub_service.private_deep_copy([])
213
234
  assert_equal([], result4)
214
235
  assert_not_same([], result4)
215
236
 
216
- result5 = @some_service.private_deep_copy({})
237
+ result5 = @stub_service.private_deep_copy({})
217
238
  assert_equal({}, result5)
218
239
  assert_not_same({}, result5)
219
240
  end
@@ -221,11 +242,11 @@ class TestSavonService < Test::Unit::TestCase
221
242
  def test_deep_copy_complex
222
243
  data = {:ab => 'ab', :cd => ['cd', 'de', 'ef']}
223
244
 
224
- result1 = @some_service.private_deep_copy(data)
245
+ result1 = @stub_service.private_deep_copy(data)
225
246
  assert_equal(data, result1)
226
247
  assert_not_same(data, result1)
227
248
 
228
- result2 = @some_service.private_deep_copy(data)
249
+ result2 = @stub_service.private_deep_copy(data)
229
250
  assert_equal(result2, result1)
230
251
  assert_not_same(result2, result1)
231
252
 
@@ -233,4 +254,29 @@ class TestSavonService < Test::Unit::TestCase
233
254
  assert_not_equal(data, result2)
234
255
  assert_equal(data, result1)
235
256
  end
257
+
258
+ def test_add_attribute
259
+ node = {}
260
+
261
+ key, name, value1, value2, value3 = 'key', 'name', 'Lorem', 'ipsum', 'dolor'
262
+
263
+ @stub_service.private_add_attribute(node, key, name, value1)
264
+ assert_kind_of(Hash, node)
265
+ assert_kind_of(Hash, node[:attributes!])
266
+ assert_kind_of(Hash, node[:attributes!][key])
267
+ assert_equal(value1, node[:attributes!][key][name])
268
+
269
+ @stub_service.private_add_attribute(node, key, name, value2)
270
+ assert_kind_of(Hash, node)
271
+ assert_kind_of(Hash, node[:attributes!])
272
+ assert_kind_of(Hash, node[:attributes!][key])
273
+ assert_kind_of(Array, node[:attributes!][key][name])
274
+ assert_equal(value1, node[:attributes!][key][name][0])
275
+ assert_equal(value2, node[:attributes!][key][name][1])
276
+
277
+ @stub_service.private_add_attribute(node, key, name, value3)
278
+ assert_equal(value1, node[:attributes!][key][name][0])
279
+ assert_equal(value2, node[:attributes!][key][name][1])
280
+ assert_equal(value3, node[:attributes!][key][name][2])
281
+ end
236
282
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-ads-common
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 0
10
- version: 0.5.0
9
+ - 1
10
+ version: 0.5.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sergio Gomes
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-08-02 00:00:00 +04:00
19
+ date: 2011-09-21 00:00:00 +04:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency