google-ads-common 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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