google-ads-common 0.5.5 → 0.6.0

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.6.0:
2
+ - Better namespace handling in complex cases.
3
+ - Large refactoring on parameter processing code.
4
+ - Support for SimpleTypes in wsdl.
5
+
1
6
  0.5.5:
2
7
  - Now support Savon 0.9.7.
3
8
 
@@ -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.5'
29
+ ADS_COMMON_VERSION = '0.6.0'
30
30
 
31
31
  # Get the available API versions.
32
32
  #
@@ -63,12 +63,16 @@ module AdsCommon
63
63
  def process_types(doc)
64
64
  REXML::XPath.each(doc, '//schema') do |schema|
65
65
  ns_index = process_namespace(schema)
66
- get_complex_types(schema).each do |ctype|
66
+ complex_types = get_complex_types(schema)
67
+ simple_types = get_simple_types(schema)
68
+ (complex_types + simple_types).each do |ctype|
67
69
  ctype_name = get_element_name(ctype)
68
70
  if ctype_name.match('.+Exception$')
69
71
  @soap_exceptions << extract_exception(ctype)
70
72
  elsif ctype_name.match('.+Error$')
71
73
  # We don't use it at the moment.
74
+ elsif ctype_name.match('.+\.Reason$')
75
+ # We don't use it at the moment.
72
76
  else
73
77
  @soap_types << extract_type(ctype, ns_index)
74
78
  end
@@ -104,6 +108,11 @@ module AdsCommon
104
108
  return REXML::XPath.each(node, 'complexType').to_a
105
109
  end
106
110
 
111
+ # Extracts SimpleTypes from node into an array.
112
+ def get_simple_types(node)
113
+ return REXML::XPath.each(node, 'simpleType').to_a
114
+ end
115
+
107
116
  # Extracts exception parameters from ComplexTypes element.
108
117
  def extract_exception(exception_element)
109
118
  return {:name => get_element_name(exception_element),
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/ruby
2
2
  #
3
- # Authors:: api.sgomes@gmail.com (Sérgio Gomes)
3
+ # Authors:: api.dklimkin@gmail.com (Danial Klimkin)
4
4
  #
5
5
  # Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
6
6
  #
@@ -20,6 +20,8 @@
20
20
  # Contains common errors across APIs, as well as base classes to inherit from
21
21
  # in specific APIs.
22
22
 
23
+ require 'pp'
24
+
23
25
  module AdsCommon
24
26
  module Errors
25
27
 
@@ -30,31 +32,53 @@ module AdsCommon
30
32
  # Raised if an attempt is made to authenticate with missing or wrong
31
33
  # information.
32
34
  class AuthError < Error
33
- attr_reader :error
34
- attr_reader :info
35
+ attr_reader :error, :info
35
36
  def initialize(message = self.class.to_s, error = nil, info = nil)
36
37
  super(message)
37
- @error = error
38
- @info = info
38
+ @error, @info = error, info
39
39
  end
40
40
  end
41
41
 
42
42
  # Raised when OAuth access token is required.
43
43
  class OAuthVerificationRequired < AuthError
44
- attr_reader :oauth_url
45
- attr_reader :request_token
44
+ attr_reader :oauth_url, :request_token
46
45
  def initialize(oauth_url, request_token)
47
46
  super()
48
47
  @oauth_url, @request_token = oauth_url, request_token
49
48
  end
50
49
  end
51
50
 
52
- # Raised if setting a non-existant property on an object
51
+ # Raised if a required property on an object is missing.
53
52
  class MissingPropertyError < Error
54
53
  attr_reader :property, :object_type
55
54
  def initialize(property, object_type)
56
- @property = property
57
- @object_type = object_type
55
+ @property, @object_type = property, object_type
56
+ end
57
+ def to_s()
58
+ return "%s: name: %s, type: %s" % [super, @property, @object_type]
59
+ end
60
+ end
61
+
62
+ # Raised if the type of the object provided does not match expected type.
63
+ class TypeMismatchError < Error
64
+ attr_reader :expected, :provided, :field_name
65
+ def initialize(expected, provided, field_name)
66
+ @expected, @provided, @field_name = expected, provided, field_name
67
+ end
68
+ def to_s()
69
+ return "%s: expected: '%s', provided: '%s' for field '%s'" %
70
+ [super, @expected, @provided, @field_name]
71
+ end
72
+ end
73
+
74
+ # Raised if unexpected parameters encountered.
75
+ class UnexpectedParametersError < Error
76
+ attr_reader :parameters_list
77
+ def initialize(parameters_list)
78
+ @parameters_list = parameters_list
79
+ end
80
+ def to_s()
81
+ return "%s: %s" % [super, PP.singleline_pp(@parameters_list, '')]
58
82
  end
59
83
  end
60
84
 
@@ -0,0 +1,270 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Author:: api.dklimkin@gmail.com (Danial Klimkin)
4
+ #
5
+ # Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
6
+ #
7
+ # License:: Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16
+ # implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ # This class validates input parameters before passing them to Savon.
21
+
22
+ module AdsCommon
23
+ class ParametersValidator
24
+ # Savon special keys.
25
+ IGNORED_HASH_KEYS = [:order!, :attributes!]
26
+
27
+ # We collect required namespaces into this hash during validation.
28
+ attr_reader :extra_namespaces
29
+
30
+ # Instance initializer.
31
+ #
32
+ # Args:
33
+ # - service: instance of savon_service to validate for
34
+ def initialize(registry)
35
+ @registry = registry
36
+ @extra_namespaces = {}
37
+ end
38
+
39
+ # Validates input parameters to:
40
+ # - add parameter names;
41
+ # - resolve xsi:type where required;
42
+ # - convert some native types to XML.
43
+ def validate_args(action_name, args)
44
+ in_params = @registry.get_method_signature(action_name)[:input]
45
+ # TODO: compare number of parameters.
46
+ args_hash = in_params.each_with_index.inject({}) do
47
+ |result, (in_param, index)|
48
+ result.merge({in_param[:name] => deep_copy(args[index])})
49
+ end
50
+ validate_arguments(args_hash, in_params)
51
+ return args_hash
52
+ end
53
+
54
+ private
55
+
56
+ # Validates given arguments based on provided fields list.
57
+ def validate_arguments(args_hash, fields_list, type_ns = nil)
58
+ check_extra_fields(args_hash, array_from_named_list(fields_list))
59
+ add_order_key(args_hash, fields_list)
60
+ fields_list.each do |field|
61
+ key = field[:name]
62
+ item = args_hash[key]
63
+ check_required_argument_present(item, field)
64
+ if item
65
+ item_type = get_full_type_signature(field[:type])
66
+ item_ns = field[:ns] || type_ns
67
+ key = handle_namespace_override(args_hash, key, item_ns) if item_ns
68
+ validate_arg(item, args_hash, key, item_type)
69
+ end
70
+ end
71
+ return args_hash
72
+ end
73
+
74
+ # Checks if no extra fields provided outside of known ones.
75
+ def check_extra_fields(args_hash, known_fields)
76
+ extra_fields = args_hash.keys - known_fields - IGNORED_HASH_KEYS
77
+ unless extra_fields.empty?
78
+ raise AdsCommon::Errors::UnexpectedParametersError.new(extra_fields)
79
+ end
80
+ end
81
+
82
+ # Generates order of XML elements for SOAP request. Adds :order! key to
83
+ # keep the correct order.
84
+ def add_order_key(args, fields_list)
85
+ all_args = fields_list.map {|field| field[:name]}
86
+ order_array = (all_args & args.keys)
87
+ args[:order!] = order_array unless order_array.empty?
88
+ end
89
+
90
+ # Checks the provided data structure matches wsdl definition.
91
+ def check_required_argument_present(arg, field)
92
+ # At least one item required, none passed.
93
+ if field[:min_occurs] > 0 and arg.nil?
94
+ raise AdsCommon::Errors::MissingPropertyError.new(
95
+ field[:name], field[:type])
96
+ end
97
+ # An object passed when an array is expected.
98
+ if (field[:max_occurs] == :unbounded) and
99
+ !(arg.nil? or arg.kind_of?(Array))
100
+ raise AdsCommon::Errors::TypeMismatchError.new(
101
+ Array, arg.class, field[:name])
102
+ end
103
+ # An array passed when an object is expected.
104
+ if (field[:max_occurs] == 1) and arg.kind_of?(Array)
105
+ raise AdsCommon::Errors::TypeMismatchError.new(
106
+ field[:type], Array)
107
+ end
108
+ end
109
+
110
+ # Overrides non-default namespace if requested.
111
+ def handle_namespace_override(args, key, ns)
112
+ add_extra_namespace(ns)
113
+ new_key = prefix_key_with_namespace(key.to_s.lower_camelcase, ns)
114
+ rename_hash_key(args, key, new_key)
115
+ replace_array_item(args[:order!], key, new_key)
116
+ return new_key
117
+ end
118
+
119
+ # Validates single argument.
120
+ def validate_arg(arg, parent, key, arg_type)
121
+ result = case arg
122
+ when Array
123
+ validate_array_arg(arg, parent, key, arg_type)
124
+ when Hash
125
+ validate_hash_arg(arg, parent, key, arg_type)
126
+ when Time
127
+ validate_time_arg(arg, parent, key)
128
+ else
129
+ arg
130
+ end
131
+ return result
132
+ end
133
+
134
+ # Validates Array argument.
135
+ def validate_array_arg(arg, parent, key, arg_type)
136
+ result = arg.map do |item|
137
+ validate_arg(item, parent, key, arg_type)
138
+ end
139
+ return result
140
+ end
141
+
142
+ # Validates Hash argument.
143
+ def validate_hash_arg(arg, parent, key, arg_type)
144
+ arg_type = handle_xsi_type(arg, parent, key, arg_type)
145
+ validate_arguments(arg, arg_type[:fields], arg_type[:ns])
146
+ end
147
+
148
+ # Validates Time argument.
149
+ def validate_time_arg(arg, parent, key)
150
+ xml_value = time_to_xml_hash(arg)
151
+ parent[key] = xml_value
152
+ return xml_value
153
+ end
154
+
155
+ # Handles custom xsi:type.
156
+ def handle_xsi_type(arg, parent, key, arg_type)
157
+ xsi_type = arg.delete('xsi:type') || arg.delete(:xsi_type)
158
+ if xsi_type
159
+ xsi_field_type = get_full_type_signature(xsi_type)
160
+ if xsi_field_type.nil?
161
+ raise AdsCommon::Errors::ApiException.new(
162
+ "Incorrect xsi:type specified: '%s'" % [xsi_type])
163
+ else
164
+ # TODO: make sure xsi_type is derived from arg_type.
165
+ arg_type = xsi_field_type
166
+ # xsi:type needs to be from a correct namespace.
167
+ if xsi_field_type[:ns]
168
+ xsi_type = prefix_key_with_namespace(xsi_type, xsi_field_type[:ns])
169
+ end
170
+ end
171
+ add_xsi_type(parent, key, xsi_type)
172
+ end
173
+ return arg_type
174
+ end
175
+
176
+ # Replaces an item in an array with a different one into the same position.
177
+ def replace_array_item(data, old_item, new_item)
178
+ data.map! {|item| (item == old_item) ? new_item : item}
179
+ end
180
+
181
+ # Replaces an item in an array with a different one into the same position.
182
+ def rename_hash_key(data, old_key, new_key)
183
+ data[new_key] = data.delete(old_key)
184
+ return data
185
+ end
186
+
187
+ # Adds ":attributes!" record for Savon to specify xsi:type.
188
+ def add_xsi_type(parent, key, xsi_type)
189
+ add_attribute(parent, key, 'xsi:type', xsi_type)
190
+ end
191
+
192
+ # Adds Savon attribute for given node, key, name and value.
193
+ def add_attribute(node, key, name, value)
194
+ node[:attributes!] ||= {}
195
+ node[:attributes!][key] ||= {}
196
+ if node[:attributes!][key].include?(name)
197
+ node[:attributes!][key][name] = arrayize(node[:attributes!][key][name])
198
+ node[:attributes!][key][name] << value
199
+ else
200
+ node[:attributes!][key][name] = value
201
+ end
202
+ end
203
+
204
+ # Prefixes a key with a given namespace index or default namespace.
205
+ def prefix_key_with_namespace(key, ns_index = nil)
206
+ namespace = (ns_index.nil?) ? DEFAULT_NAMESPACE : ("ns%d" % ns_index)
207
+ return prefix_key(key, namespace)
208
+ end
209
+
210
+ # Prefixes with a given namespace.
211
+ def prefix_key(key, ns)
212
+ return [ns, key].join(':')
213
+ end
214
+
215
+ # Returns list of 'names' for objects in array.
216
+ def array_from_named_list(fields_list)
217
+ return fields_list.map {|field| field[:name]}
218
+ end
219
+
220
+ # Returns copy of object and its sub-objects ("deep" copy).
221
+ def deep_copy(data)
222
+ return Marshal.load(Marshal.dump(data))
223
+ end
224
+
225
+ # Returns type signature with all inherited fields.
226
+ def get_full_type_signature(type_name)
227
+ result = (type_name.nil?) ? nil : @registry.get_type_signature(type_name)
228
+ result[:fields] = implode_parent(result) if result and result[:base]
229
+ return result
230
+ end
231
+
232
+ # Returns all inherited fields of superclasses for given type.
233
+ def implode_parent(data_type)
234
+ result = []
235
+ if data_type[:base]
236
+ parent_type = @registry.get_type_signature(data_type[:base])
237
+ result += implode_parent(parent_type)
238
+ end
239
+ data_type[:fields].each do |field|
240
+ # If the parent type includes a field with the same name, overwrite it.
241
+ result.reject! {|parent_field| parent_field[:name].eql?(field[:name])}
242
+ # Storing field's namespace.
243
+ field[:ns] = data_type[:ns] if data_type[:ns]
244
+ result << field
245
+ end
246
+ return result
247
+ end
248
+
249
+ # Adds additional namespace for XML generation.
250
+ def add_extra_namespace(ns_index)
251
+ @extra_namespaces.merge!({
252
+ "xmlns:ns%d" % ns_index => @registry.get_namespace(ns_index)
253
+ })
254
+ end
255
+
256
+ # Makes sure object is an array.
257
+ def arrayize(object)
258
+ return [] if object.nil?
259
+ return object.is_a?(Array) ? object : [object]
260
+ end
261
+
262
+ # Converts Time to a hash for XML marshalling.
263
+ def time_to_xml_hash(time)
264
+ return {
265
+ :hour => time.hour, :minute => time.min, :second => time.sec,
266
+ :date => {:year => time.year, :month => time.month, :day => time.day}
267
+ }
268
+ end
269
+ end
270
+ end
@@ -87,8 +87,8 @@ module AdsCommon
87
87
  credentials = @credential_handler.credentials(@version)
88
88
  app_name = credentials[:userAgent] || credentials[:useragent]
89
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.5'
90
+ # introduced. This is scheduled for 0.7.0, using Common version for now.
91
+ lib_version = '0.6.0'
92
92
  soap_user_agent = "Common-Ruby-%s; %s" % [lib_version, app_name]
93
93
  return "Savon/%s (%s)" % [Savon::Version, soap_user_agent]
94
94
  end
@@ -22,11 +22,10 @@
22
22
  require 'httpi'
23
23
  require 'savon'
24
24
 
25
+ require 'ads_common/parameters_validator'
26
+
25
27
  module AdsCommon
26
28
  class SavonService
27
- # Default namespace name.
28
- DEFAULT_NAMESPACE = 'wsdl'
29
-
30
29
  # HTTP read timeout in seconds.
31
30
  HTTP_READ_TIMEOUT = 15 * 60
32
31
 
@@ -81,164 +80,31 @@ module AdsCommon
81
80
 
82
81
  # Executes SOAP action specified as a string with given arguments.
83
82
  def execute_action(action_name, args, &block)
84
- args = validate_args(action_name, args)
85
- response = execute_soap_request(action_name.to_sym, args)
83
+ validator = ParametersValidator.new(get_service_registry())
84
+ args = validator.validate_args(action_name, args)
85
+ response = execute_soap_request(
86
+ action_name.to_sym, args, validator.extra_namespaces)
86
87
  handle_errors(response)
87
88
  return extract_result(response, action_name, &block)
88
89
  end
89
90
 
90
91
  # Executes the SOAP request with original SOAP name.
91
- def execute_soap_request(action, args)
92
+ def execute_soap_request(action, args, extra_namespaces)
92
93
  original_action_name =
93
94
  get_service_registry.get_method_signature(action)[:original_name]
94
95
  original_action_name = action if original_action_name.nil?
95
96
  response = @client.request(original_action_name) do |soap|
96
- set_headers(soap, args)
97
+ set_headers(soap, args, extra_namespaces)
97
98
  end
98
99
  return response
99
100
  end
100
101
 
101
- # Validates input parameters to:
102
- # - add parameter names;
103
- # - resolve xsi:type where required;
104
- # - convert some native types to XML.
105
- def validate_args(action_name, args)
106
- validated_args = {}
107
- in_params = get_service_registry.get_method_signature(action_name)[:input]
108
- in_params.each_with_index do |in_param, index|
109
- key = in_param[:name]
110
- value = deep_copy(args[index])
111
- validated_args[key] = (value.nil?) ?
112
- nil : validate_arg(value, validated_args, key, in_param[:type])
113
- # Adding :order! key to keep correct order in SOAP elements.
114
- validated_args[:order!] =
115
- generate_order_for_args(validated_args, in_params)
116
- end
117
- return validated_args
118
- end
119
-
120
- # Validates method argument. Runs recursively if hash or array encountered.
121
- # Also handles some types that need special conversions.
122
- def validate_arg(arg, parent = nil, key = nil, field_type_name = nil)
123
- field_type = get_full_type_signature(field_type_name)
124
- result = case arg
125
- when Hash
126
- validate_hash_arg(arg, parent, key, field_type)
127
- when Array then arg.map do |item|
128
- validate_arg(item, parent, key, field_type_name)
129
- end
130
- when Time then time_to_xml_hash(arg)
131
- else arg
132
- end
133
- return result
134
- end
135
-
136
- # Generates order of XML elements for SOAP request. Returns only items
137
- # existing in arg.
138
- def generate_order_for_args(arg, fields)
139
- all_keys = fields.map {|field| field[:name]}
140
- return all_keys & arg.keys
141
- end
142
-
143
- # Validates hash argument recursively. Keeps tracking of correct place
144
- # for xsi:type and adds is when required.
145
- def validate_hash_arg(arg, parent = nil, key = nil, field_type = nil)
146
- # Non-default namespace should be used, overriding default.
147
- if field_type and field_type.include?(:ns)
148
- namespace = get_service_registry.get_namespace(field_type[:ns])
149
- key = prefix_key(key)
150
- add_attribute(parent, key, 'xmlns', namespace)
151
- end
152
-
153
- # Handling custom xsi:type.
154
- xsi_type = arg.delete('xsi:type') || arg.delete(:xsi_type)
155
- if xsi_type
156
- xsi_field_type = get_full_type_signature(xsi_type)
157
- if xsi_field_type.nil?
158
- raise AdsCommon::Errors::ApiException.new(
159
- "Incorrect xsi:type specified: '%s'" % [xsi_type])
160
- else
161
- # TODO: make sure xsi_type is derived from field_type.
162
- field_type = xsi_field_type
163
- end
164
- if parent and key
165
- add_xsi_type(parent, key, xsi_type)
166
- else
167
- raise AdsCommon::Errors::ApiException.new(
168
- "Can't find correct position for xsi:type (%s) [%s], [%s]" %
169
- [xsi_type, parent, key])
170
- end
171
- end
172
-
173
- # Adding :order! key to keep correct order in SOAP elements.
174
- if field_type and field_type.include?(:fields)
175
- arg[:order!] =
176
- generate_order_for_args(arg, field_type[:fields])
177
- end
178
-
179
- # Processing each key-value pair.
180
- return arg.inject({}) do |result, (k, v)|
181
- if (k == :attributes! or k == :order!)
182
- result[k] = v
183
- else
184
- subfield = (field_type.nil?) ? nil :
185
- get_field_by_name(field_type[:fields], k)
186
- # Here we will give up if the field is unknown. For full validation
187
- # we have to handle nil here.
188
- subtype_name, subtype = if subfield and subfield.include?(:type)
189
- subtype_name = subfield[:type]
190
- subtype = (subtype_name.nil?) ? nil :
191
- get_service_registry.get_type_signature(subtype_name)
192
- [subtype_name, subtype]
193
- end
194
- # In case of non-default namespace, the children should be in
195
- # overridden namespace but the node has to be in the default.
196
- # We also have to fix order! list if we alter the key name.
197
- new_key = if (subtype and subtype[:ns])
198
- prefixed_key = prefix_key(k)
199
- replace_item!(arg[:order!], k, prefixed_key)
200
- prefixed_key
201
- else
202
- k
203
- end
204
- result[new_key] = validate_arg(v, result, k, subtype_name)
205
- end
206
- result
207
- end
208
- end
209
-
210
- # Replaces an item in an array with a different one into the same position.
211
- def replace_item!(data, old_item, new_item)
212
- data.map! {|item| (item == old_item) ? new_item : item}
213
- end
214
-
215
- # Adds ":attributes!" record for Savon to specify xsi:type.
216
- def add_xsi_type(parent, key, xsi_type)
217
- add_attribute(parent, key, 'xsi:type', xsi_type)
218
- end
219
-
220
- # Adds Savon attribute for given node, key, name and value.
221
- def add_attribute(node, key, name, value)
222
- node[:attributes!] ||= {}
223
- node[:attributes!][key] ||= {}
224
- if node[:attributes!][key].include?(name)
225
- node[:attributes!][key][name] = arrayize(node[:attributes!][key][name])
226
- node[:attributes!][key][name] << value
227
- else
228
- node[:attributes!][key][name] = value
229
- end
230
- end
231
-
232
- # Prefixes default namespace.
233
- def prefix_key(key)
234
- return "%s:%s" % [DEFAULT_NAMESPACE, key.to_s.lower_camelcase]
235
- end
236
-
237
102
  # Executes each handler to generate SOAP headers.
238
- def set_headers(soap, args)
103
+ def set_headers(soap, args, extra_namespaces)
239
104
  @headerhandler.each do |handler|
240
105
  handler.prepare_request(@client.http, soap, args)
241
106
  end
107
+ soap.namespaces.merge!(extra_namespaces) unless extra_namespaces.nil?
242
108
  end
243
109
 
244
110
  # Checks for errors in response and raises appropriate exception.
@@ -405,14 +271,6 @@ module AdsCommon
405
271
  return object.is_a?(Array) ? object : [object]
406
272
  end
407
273
 
408
- # Converts Time to a hash for XML marshalling.
409
- def time_to_xml_hash(time)
410
- return {
411
- :hour => time.hour, :minute => time.min, :second => time.sec,
412
- :date => {:year => time.year, :month => time.month, :day => time.day}
413
- }
414
- end
415
-
416
274
  # Returns all inherited fields of superclasses for given type.
417
275
  def implode_parent(data_type)
418
276
  result = []
@@ -428,11 +286,6 @@ module AdsCommon
428
286
  return result
429
287
  end
430
288
 
431
- # Returns copy of object and its sub-objects ("deep" copy).
432
- def deep_copy(data)
433
- return Marshal.load(Marshal.dump(data))
434
- end
435
-
436
289
  # Returns type signature with all inherited fields.
437
290
  def get_full_type_signature(type_name)
438
291
  result = (type_name.nil?) ? nil :
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Author:: api.dklimkin@gmail.com (Danial Klimkin)
4
+ #
5
+ # Copyright:: Copyright 2011, Google Inc. All Rights Reserved.
6
+ #
7
+ # License:: Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16
+ # implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+ # Tests validator methods.
21
+
22
+ require 'rubygems'
23
+ require 'test/unit'
24
+
25
+ require 'ads_common/parameters_validator'
26
+
27
+ module AdsCommon
28
+ class ParametersValidator
29
+ public :deep_copy, :add_attribute, :array_from_named_list
30
+ end
31
+ end
32
+
33
+ class TestParametersValidator < Test::Unit::TestCase
34
+ def setup
35
+ @validator = AdsCommon::ParametersValidator.new(nil)
36
+ end
37
+
38
+ def test_deep_copy_simple
39
+ result1 = @validator.deep_copy(42)
40
+ assert_equal(42, result1)
41
+
42
+ result2 = @validator.deep_copy('Hello World')
43
+ assert_equal('Hello World', result2)
44
+
45
+ result3 = @validator.deep_copy(nil)
46
+ assert_nil(result3)
47
+
48
+ result4 = @validator.deep_copy([])
49
+ assert_equal([], result4)
50
+ assert_not_same([], result4)
51
+
52
+ result5 = @validator.deep_copy({})
53
+ assert_equal({}, result5)
54
+ assert_not_same({}, result5)
55
+ end
56
+
57
+ def test_deep_copy_complex
58
+ data = {:ab => 'ab', :cd => ['cd', 'de', 'ef']}
59
+
60
+ result1 = @validator.deep_copy(data)
61
+ assert_equal(data, result1)
62
+ assert_not_same(data, result1)
63
+
64
+ result2 = @validator.deep_copy(data)
65
+ assert_equal(result2, result1)
66
+ assert_not_same(result2, result1)
67
+
68
+ result2[:cd] = nil
69
+ assert_not_equal(data, result2)
70
+ assert_equal(data, result1)
71
+ end
72
+
73
+ def test_add_attribute
74
+ node = {}
75
+
76
+ key, name, value1, value2, value3 = 'key', 'name', 'Lorem', 'ipsum', 'dolor'
77
+
78
+ @validator.add_attribute(node, key, name, value1)
79
+ assert_kind_of(Hash, node)
80
+ assert_kind_of(Hash, node[:attributes!])
81
+ assert_kind_of(Hash, node[:attributes!][key])
82
+ assert_equal(value1, node[:attributes!][key][name])
83
+
84
+ @validator.add_attribute(node, key, name, value2)
85
+ assert_kind_of(Hash, node)
86
+ assert_kind_of(Hash, node[:attributes!])
87
+ assert_kind_of(Hash, node[:attributes!][key])
88
+ assert_kind_of(Array, node[:attributes!][key][name])
89
+ assert_equal(value1, node[:attributes!][key][name][0])
90
+ assert_equal(value2, node[:attributes!][key][name][1])
91
+
92
+ @validator.add_attribute(node, key, name, value3)
93
+ assert_equal(value1, node[:attributes!][key][name][0])
94
+ assert_equal(value2, node[:attributes!][key][name][1])
95
+ assert_equal(value3, node[:attributes!][key][name][2])
96
+ end
97
+
98
+ def test_array_from_named_list
99
+ src = [{:name => 'foo'}, {:name => 'bar', :bar => :baz}, {:name => 'ipsum'}]
100
+ result = @validator.array_from_named_list(src)
101
+ assert_equal(['foo', 'bar', 'ipsum'], result)
102
+ end
103
+ end
@@ -219,64 +219,4 @@ class TestSavonService < Test::Unit::TestCase
219
219
  assert_instance_of(Float, result4)
220
220
  assert_equal(42.0, result4, 'Float is expected for nil max_occurs')
221
221
  end
222
-
223
- def test_deep_copy_simple
224
- result1 = @stub_service.private_deep_copy(42)
225
- assert_equal(42, result1)
226
-
227
- result2 = @stub_service.private_deep_copy('Hello World')
228
- assert_equal('Hello World', result2)
229
-
230
- result3 = @stub_service.private_deep_copy(nil)
231
- assert_nil(result3)
232
-
233
- result4 = @stub_service.private_deep_copy([])
234
- assert_equal([], result4)
235
- assert_not_same([], result4)
236
-
237
- result5 = @stub_service.private_deep_copy({})
238
- assert_equal({}, result5)
239
- assert_not_same({}, result5)
240
- end
241
-
242
- def test_deep_copy_complex
243
- data = {:ab => 'ab', :cd => ['cd', 'de', 'ef']}
244
-
245
- result1 = @stub_service.private_deep_copy(data)
246
- assert_equal(data, result1)
247
- assert_not_same(data, result1)
248
-
249
- result2 = @stub_service.private_deep_copy(data)
250
- assert_equal(result2, result1)
251
- assert_not_same(result2, result1)
252
-
253
- result2[:cd] = nil
254
- assert_not_equal(data, result2)
255
- assert_equal(data, result1)
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
282
222
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
8
- - 5
9
- version: 0.5.5
7
+ - 6
8
+ - 0
9
+ version: 0.6.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Sergio Gomes
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-28 00:00:00 +04:00
18
+ date: 2011-12-02 00:00:00 +04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -89,27 +89,29 @@ extra_rdoc_files:
89
89
  - COPYING
90
90
  - ChangeLog
91
91
  files:
92
- - lib/ads_common/auth/base_handler.rb
93
92
  - lib/ads_common/auth/client_login_handler.rb
93
+ - lib/ads_common/auth/base_handler.rb
94
94
  - lib/ads_common/auth/oauth_handler.rb
95
- - lib/ads_common/build/savon_abstract_generator.rb
95
+ - lib/ads_common/credential_handler.rb
96
96
  - lib/ads_common/build/savon_generator.rb
97
- - lib/ads_common/build/savon_registry.rb
98
97
  - lib/ads_common/build/savon_registry_generator.rb
98
+ - lib/ads_common/build/savon_registry.rb
99
99
  - lib/ads_common/build/savon_service_generator.rb
100
- - lib/ads_common/savon_headers/base_header_handler.rb
101
- - lib/ads_common/savon_headers/httpi_request_proxy.rb
102
- - lib/ads_common/savon_headers/oauth_header_handler.rb
103
- - lib/ads_common/savon_headers/simple_header_handler.rb
100
+ - lib/ads_common/build/savon_abstract_generator.rb
104
101
  - lib/ads_common/api_config.rb
105
- - lib/ads_common/api.rb
106
102
  - lib/ads_common/config.rb
107
- - lib/ads_common/credential_handler.rb
108
- - lib/ads_common/errors.rb
109
- - lib/ads_common/http.rb
103
+ - lib/ads_common/api.rb
104
+ - lib/ads_common/savon_headers/base_header_handler.rb
105
+ - lib/ads_common/savon_headers/simple_header_handler.rb
106
+ - lib/ads_common/savon_headers/oauth_header_handler.rb
107
+ - lib/ads_common/savon_headers/httpi_request_proxy.rb
110
108
  - lib/ads_common/savon_service.rb
109
+ - lib/ads_common/http.rb
110
+ - lib/ads_common/parameters_validator.rb
111
+ - lib/ads_common/errors.rb
111
112
  - Rakefile
112
113
  - test/test_config.rb
114
+ - test/test_parameters_validator.rb
113
115
  - test/test_savon_service.rb
114
116
  - README
115
117
  - COPYING
@@ -148,4 +150,5 @@ specification_version: 3
148
150
  summary: Common code for Google Ads APIs.
149
151
  test_files:
150
152
  - test/test_config.rb
153
+ - test/test_parameters_validator.rb
151
154
  - test/test_savon_service.rb