testability-driver 0.9.2 → 1.0.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.
Files changed (108) hide show
  1. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_composition.rb +1 -1
  2. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_description.rb +11 -7
  3. data/lib/tdriver/base/behaviour/behaviours/object_composition.rb +8 -0
  4. data/lib/tdriver/base/behaviour/factory.rb +229 -209
  5. data/lib/tdriver/base/errors.rb +3 -0
  6. data/lib/tdriver/base/state_object.rb +11 -20
  7. data/lib/tdriver/base/sut/controller.rb +4 -4
  8. data/lib/tdriver/base/sut/factory.rb +205 -170
  9. data/lib/tdriver/base/sut/generic/behaviours/application.rb +256 -174
  10. data/lib/tdriver/base/sut/generic/behaviours/find.rb +17 -11
  11. data/lib/tdriver/base/sut/generic/behaviours/flash_behaviour.rb +57 -66
  12. data/lib/tdriver/base/sut/generic/behaviours/sut.rb +578 -497
  13. data/lib/tdriver/base/sut/generic/behaviours/switchbox_behaviour.rb +41 -15
  14. data/lib/tdriver/base/sut/generic/behaviours/verification.rb +48 -19
  15. data/lib/tdriver/base/sut/generic/commands/fixture.rb +47 -0
  16. data/lib/tdriver/base/sut/generic/commands/key_sequence.rb +25 -13
  17. data/lib/tdriver/base/sut/generic/commands/screen_capture.rb +16 -10
  18. data/lib/tdriver/base/sut/generic/plugin.rb +9 -3
  19. data/lib/tdriver/base/sut/sut.rb +41 -33
  20. data/lib/tdriver/base/test_object/abstract.rb +26 -3
  21. data/lib/tdriver/base/test_object/adapter.rb +399 -0
  22. data/lib/tdriver/base/test_object/behaviours/syncronization.rb +56 -14
  23. data/lib/tdriver/base/test_object/behaviours/test_object.rb +663 -197
  24. data/lib/tdriver/base/test_object/cache.rb +132 -0
  25. data/lib/tdriver/base/test_object/factory.rb +677 -426
  26. data/lib/tdriver/base/test_object/factory_new.rb +202 -0
  27. data/lib/tdriver/base/test_object/identificator.rb +24 -17
  28. data/lib/tdriver/base/test_object/loader.rb +9 -3
  29. data/lib/tdriver/base/test_object/verification.rb +181 -0
  30. data/lib/tdriver/loader.rb +1 -1
  31. data/lib/tdriver/report/report.rb +2 -0
  32. data/lib/tdriver/report/report_api.rb +4 -4
  33. data/lib/tdriver/report/report_creator.rb +29 -3
  34. data/lib/tdriver/report/report_data_presentation.rb +7 -3
  35. data/lib/tdriver/report/report_execution_statistics.rb +80 -21
  36. data/lib/tdriver/report/report_javascript.rb +192 -0
  37. data/lib/tdriver/report/report_test_case_run.rb +22 -0
  38. data/lib/tdriver/report/report_test_run.rb +62 -55
  39. data/lib/tdriver/report/report_writer.rb +57 -56
  40. data/lib/tdriver/tdriver.rb +14 -41
  41. data/lib/tdriver/util/common/error.rb +1 -0
  42. data/lib/tdriver/util/common/exceptions.rb +12 -0
  43. data/lib/tdriver/util/common/file.rb +12 -6
  44. data/lib/tdriver/util/common/gem.rb +2 -1
  45. data/lib/tdriver/util/common/hash.rb +152 -0
  46. data/lib/tdriver/util/common/kernel.rb +49 -34
  47. data/lib/tdriver/util/common/loader.rb +21 -17
  48. data/lib/tdriver/util/common/numeric.rb +39 -0
  49. data/lib/tdriver/util/common/object.rb +115 -0
  50. data/lib/tdriver/util/common/string.rb +55 -2
  51. data/lib/tdriver/util/dbaccess/dbaccess.rb +194 -161
  52. data/lib/tdriver/util/dynamic_attribute_filter.rb +6 -0
  53. data/lib/tdriver/util/hooking.rb +2 -2
  54. data/lib/tdriver/util/loader.rb +2 -2
  55. data/lib/tdriver/util/localisation/localisation.rb +277 -18
  56. data/lib/tdriver/util/logger.rb +142 -13
  57. data/lib/tdriver/util/parameter/parameter_hash.rb +8 -5
  58. data/lib/tdriver/util/parameter/parameter_xml.rb +18 -2
  59. data/lib/tdriver/util/recorder.rb +17 -12
  60. data/lib/tdriver/util/user_data/user_data.rb +3 -2
  61. data/lib/tdriver/util/{video_rec.rb → video_utils.rb} +136 -16
  62. data/lib/tdriver/util/xml/abstraction.rb +7 -0
  63. data/lib/tdriver/util/xml/attribute.rb +32 -0
  64. data/lib/tdriver/util/xml/loader.rb +8 -2
  65. data/lib/tdriver/util/xml/nil_node.rb +95 -0
  66. data/lib/tdriver/util/xml/parsers/nokogiri/abstraction.rb +46 -7
  67. data/lib/tdriver/util/xml/parsers/nokogiri/attribute.rb +19 -9
  68. data/lib/tdriver/util/xml/parsers/nokogiri/document.rb +1 -1
  69. data/lib/tdriver/util/xml/parsers/nokogiri/element.rb +13 -1
  70. data/lib/tdriver/util/xml/parsers/nokogiri/loader.rb +6 -0
  71. data/lib/tdriver/util/xml/parsers/nokogiri/nodeset.rb +27 -15
  72. data/lib/tdriver/util/xml/parsers/nokogiri/text.rb +57 -0
  73. data/lib/tdriver/util/xml/text.rb +32 -0
  74. data/lib/tdriver/util/xml/xml.rb +35 -22
  75. data/lib/tdriver/version.rb +1 -1
  76. data/lib/tdriver-devtools/behaviour/xml/rdoc_behaviour_xml_generator.rb +41 -34
  77. data/lib/tdriver-devtools/doc/generate.rb +31 -6
  78. data/lib/tdriver-devtools/doc/xslt/template.xsl +46 -25
  79. data/lib/tdriver-devtools/tests/feature_tests/example/behaviour_example.rb +100 -0
  80. data/lib/tdriver-devtools/tests/feature_tests/update +1 -1
  81. data/lib/tdriver.rb +0 -3
  82. data/xml/behaviours/generic.xml +1 -1
  83. data/xml/defaults/generic.xml +4 -90
  84. data/xml/templates/generic.xml +33 -25
  85. metadata +21 -29
  86. data/lib/tdriver-devtools/behaviour/xml_generator/example/flick-example.rb +0 -245
  87. data/lib/tdriver-devtools/behaviour/xml_generator/example/sut.rb +0 -964
  88. data/lib/tdriver-devtools/behaviour/xml_generator/generate.rb +0 -68
  89. data/lib/tdriver-devtools/behaviour/xml_generator/lib/custom_rdoc_generator.rb +0 -1865
  90. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument.default.template +0 -1
  91. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument.template +0 -3
  92. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.argument_type.template +0 -4
  93. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.exception.template +0 -4
  94. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.arguments.template +0 -4
  95. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.deprecated.template +0 -3
  96. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.exceptions.template +0 -3
  97. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.info.template +0 -1
  98. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.returns.template +0 -3
  99. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.tables.template +0 -3
  100. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.method.template +0 -12
  101. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.returns.template +0 -5
  102. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.item.template +0 -1
  103. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.row.template +0 -2
  104. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.table.template +0 -7
  105. data/lib/tdriver-devtools/behaviour/xml_generator/templates/behaviour.xml.template +0 -14
  106. data/lib/tdriver-devtools/behaviour/xml_generator/update +0 -3
  107. data/lib/tdriver-devtools/tests/feature_tests/example/flick-example.rb +0 -233
  108. data/lib/tdriver-devtools/tests/feature_tests/example/impl.rb +0 -194
@@ -1,3 +1,4 @@
1
+ ############################################################################
1
2
  ##
2
3
  ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
3
4
  ## All rights reserved.
@@ -60,7 +61,9 @@ module MobyBase
60
61
  # === raises
61
62
  # nothing
62
63
  def eql?( other_test_object )
64
+
63
65
  self == other_test_object
66
+
64
67
  end
65
68
 
66
69
  # Function to verify is DATA of two TestObjects are the same,
@@ -85,7 +88,10 @@ module MobyBase
85
88
  #return true
86
89
 
87
90
  # optimized version
88
- other_test_object.instance_of?( MobyBase::TestObject ) && ( @type == other_test_object.type ) && ( @id == other_test_object.id ) && (@name == other_test_object.name )
91
+ other_test_object.instance_of?( MobyBase::TestObject ) &&
92
+ ( @type == other_test_object.type ) &&
93
+ ( @id == other_test_object.id ) &&
94
+ ( @name == other_test_object.name )
89
95
 
90
96
  end
91
97
 
@@ -97,6 +103,7 @@ module MobyBase
97
103
  # Fixnum:: hash number representing current TestObject
98
104
  def hash
99
105
 
106
+
100
107
  #result = 17
101
108
  #result = result * 37 + self.id.to_i
102
109
  #result = result * 37 + type.hash
@@ -104,7 +111,9 @@ module MobyBase
104
111
  #return result
105
112
 
106
113
  # optimized version
107
- ( ( ( 17 * 37 + @id.to_i ) * 37 + @type.hash ) * 37 + @name.hash )
114
+ #( ( ( 17 * 37 + @id.to_i ) * 37 + @type.hash ) * 37 + @name.hash )
115
+
116
+ TDriver::TestObjectAdapter.test_object_hash( @id.to_i, @type, @name )
108
117
 
109
118
  end
110
119
 
@@ -153,6 +162,13 @@ module MobyBase
153
162
 
154
163
  end
155
164
 
165
+ # TODO: document me
166
+ def inspect
167
+
168
+ "#<#{ self.class }:0x#{ ( "%x" % ( self.object_id.to_i << 1 ) )[ 3 .. -1 ] } @id=\"#{ @id }\" @name=\"#{ @name }\" @parent=#{ @parent.inspect } @sut=#{ @sut.inspect } @type=\"#{ @type }\" @x_path=\"#{ @x_path }\">"
169
+
170
+ end
171
+
156
172
  # Returns a XML node representing this test object.
157
173
  #
158
174
  # === returns
@@ -165,7 +181,14 @@ module MobyBase
165
181
 
166
182
  #Kernel::raise MobyBase::TestObjectNotFoundError.new( "The test object with id: \"#{ @id.to_s }\", type: \"#{ @type.to_s }\" and name: \"#{ @name.to_s }\" does not exist on sut \"#{ @sut.id.to_s }\" anymore" ) if ( elements = @sut.xml_data.xpath( @x_path ) ).size.zero?
167
183
 
168
- Kernel::raise MobyBase::TestObjectNotFoundError.new( 'The test object (id: "%s", type: "%s", name: "%s") does not exist on sut (%s) anymore' % [ @id, @type, @name, @sut.id ] ) if ( elements = @sut.xml_data.xpath( @x_path ) ).size.zero?
184
+ elements = @sut.xml_data.xpath( @x_path )
185
+
186
+ Kernel::raise MobyBase::TestObjectNotFoundError.new(
187
+
188
+ #'The test object (id: "%s", type: "%s", name: "%s") does not exist on sut (%s) anymore' % [ @id, @type, @name, @sut.id ]
189
+ "The test object (id: #{ @id.inspect }, type: #{ @type.inspect }, name: #{ @name.inspect }) does not exist on sut (#{ @sut.id.inspect }) anymore"
190
+
191
+ ) if elements.size.zero?
169
192
 
170
193
  elements.first
171
194
 
@@ -0,0 +1,399 @@
1
+ ############################################################################
2
+ ##
3
+ ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4
+ ## All rights reserved.
5
+ ## Contact: Nokia Corporation (testabilitydriver@nokia.com)
6
+ ##
7
+ ## This file is part of Testability Driver.
8
+ ##
9
+ ## If you have questions regarding the use of this file, please contact
10
+ ## Nokia at testabilitydriver@nokia.com .
11
+ ##
12
+ ## This library is free software; you can redistribute it and/or
13
+ ## modify it under the terms of the GNU Lesser General Public
14
+ ## License version 2.1 as published by the Free Software Foundation
15
+ ## and appearing in the file LICENSE.LGPL included in the packaging
16
+ ## of this file.
17
+ ##
18
+ ############################################################################
19
+
20
+ module TDriver
21
+
22
+ class TestObjectAdapter
23
+
24
+ # private methods and variables
25
+ class << self
26
+
27
+ private
28
+
29
+ # special cases: allow partial match when value of type and attribute name matches
30
+ @@partial_match_allowed = [ 'list_item', 'text' ], ['application', 'fullname' ]
31
+
32
+ def xpath_attributes( attributes, element_attributes, object_type )
33
+
34
+ attributes = attributes.collect{ | key, values |
35
+
36
+ values = ( values.kind_of?( Array ) ? values : [ values ] ).collect{ | value |
37
+
38
+ # concatenate string if it contains single and double quotes, otherwise return as is
39
+ value = xpath_literal_string( value )
40
+
41
+ if @@partial_match_allowed.include?( [ object_type, key ] )
42
+
43
+ # partial match allowed
44
+ value = "[contains(.,#{ value })]"
45
+
46
+ else
47
+
48
+ # exact match required
49
+ value = "=#{ value }"
50
+
51
+ end
52
+
53
+ if element_attributes
54
+
55
+ prefix = "@#{key}#{value} or "
56
+
57
+ else
58
+
59
+ prefix = ""
60
+
61
+ end
62
+
63
+ "#{ prefix }attributes/attribute[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{key}' and .#{value}]"
64
+
65
+ }.join( " or " )
66
+
67
+ }
68
+
69
+ result = attributes.join(' and ')
70
+
71
+ if result.empty?
72
+
73
+ result = nil
74
+
75
+ else
76
+
77
+ result = "(#{ result })" if element_attributes
78
+
79
+ end
80
+
81
+ result
82
+
83
+ end
84
+
85
+
86
+ end
87
+
88
+ # TODO: document me
89
+ def self.xpath_to_object( rules, find_all_children )
90
+
91
+ # convert hash keys to downcased string
92
+ rules = Hash[ rules.collect{ | key, value | [ key.to_s.downcase, value ] } ]
93
+
94
+ test_object_identification_attributes_array = []
95
+
96
+ # store and remove object element attributes from hash
97
+ object_element_attributes = rules.delete_keys!( "name", "type", "parent", "id" )
98
+
99
+ # TODO: change "any" to "*"
100
+ # children method may request test objects of any type
101
+ if object_element_attributes[ "type" ] == 'any'
102
+
103
+ # test object with any name, type, parent and id is allowed
104
+ test_object_identification_attributes_array << '@*'
105
+
106
+ else
107
+
108
+ # required attributes
109
+ test_object_identification_attributes_array << xpath_attributes( object_element_attributes, true, object_element_attributes[ "type" ] )
110
+
111
+ end
112
+
113
+ # additional attributes, eg. :text, :x, :y etc.
114
+ test_object_identification_attributes_array << xpath_attributes( rules, false, object_element_attributes[ "type" ] )
115
+
116
+ # join required and additional attribute strings
117
+ test_object_identification_attributes = test_object_identification_attributes_array.compact.join(" and ")
118
+
119
+ find_all_children ? "*//object[#{ test_object_identification_attributes }]" : "objects[1]/object[#{ test_object_identification_attributes }]"
120
+
121
+ end
122
+
123
+ # TODO: document me
124
+ def self.xpath_literal_string( string )
125
+
126
+ # make sure that argument is type of string
127
+ string = string.to_s
128
+
129
+ # does not contain no single quotes
130
+ if not string.include?("'")
131
+
132
+ result = "'#{ string }'"
133
+
134
+ # does not contain no double quotes
135
+ elsif not string.include?('"')
136
+
137
+ result = "\"#{ string }\""
138
+
139
+ # contains single and double quotes
140
+ else
141
+
142
+ # open new item
143
+ result = ["'"]
144
+
145
+ # iterate through each character
146
+ string.each_char{ | char |
147
+
148
+ case char
149
+
150
+ # encapsulate single quotes with double quotes
151
+ when "'"
152
+
153
+ # close current item
154
+ result.last << char
155
+
156
+ # add encapsulated single quote
157
+ result << "\"'\""
158
+
159
+ # open new item
160
+ result << char
161
+
162
+ else
163
+
164
+ # any other character will appended as is
165
+ result.last << char
166
+
167
+ end
168
+
169
+ }
170
+
171
+ # close last sentence
172
+ result.last << "'"
173
+
174
+ # create concat clause for xpath
175
+ result = "concat(#{ result.join(',') })"
176
+
177
+ end
178
+
179
+ result
180
+
181
+ end
182
+
183
+ # TODO: document me
184
+ def self.get_objects( source_data, rules, find_all_children )
185
+
186
+ rule = xpath_to_object( rules, find_all_children )
187
+
188
+ [
189
+ # perform xpath to source xml data
190
+ source_data.xpath( rule ),
191
+ rule
192
+ ]
193
+
194
+ end
195
+
196
+ def self.test_object_hash( object_id, object_type, object_name )
197
+
198
+ ( ( ( 17 * 37 + object_id ) * 37 + object_type.hash ) * 37 + object_name.hash )
199
+
200
+ end
201
+
202
+ # Sort XML nodeset of test objects with layout direction
203
+ def self.sort_elements( nodeset, layout_direction = "LeftToRight" )
204
+
205
+ attribute_pattern = "./attributes/attribute[@name='%s']/value/text()"
206
+
207
+ # collect only nodes that has x_absolute and y_absolute attributes
208
+ nodeset.collect!{ | node |
209
+
210
+ #node unless node.at_xpath( attribute_pattern % 'x_absolute' ).to_s.empty? || node.at_xpath( attribute_pattern % 'y_absolute' ).to_s.empty?
211
+ node unless node.at_xpath( attribute_pattern % 'x_absolute' ).nil? || node.at_xpath( attribute_pattern % 'y_absolute' ).nil?
212
+
213
+ }.compact!.sort!{ | element_a, element_b |
214
+
215
+ element_a_x = element_a.at_xpath( attribute_pattern % 'x_absolute' ).content.to_i
216
+ element_a_y = element_a.at_xpath( attribute_pattern % 'y_absolute' ).content.to_i
217
+
218
+ element_b_x = element_b.at_xpath( attribute_pattern % 'x_absolute' ).content.to_i
219
+ element_b_y = element_b.at_xpath( attribute_pattern % 'y_absolute' ).content.to_i
220
+
221
+ case layout_direction
222
+
223
+ when "LeftToRight"
224
+
225
+ ( element_a_y == element_b_y ) ? ( element_a_x <=> element_b_x ) : ( element_a_y <=> element_b_y )
226
+
227
+ when "RightToLeft"
228
+
229
+ ( element_a_y == element_b_y ) ? ( element_b_x <=> element_a_x ) : ( element_a_y <=> element_b_y )
230
+
231
+ else
232
+
233
+ Kernel::raise ArgumentError.new( "Unsupported layout direction #{ layout_direction.inspect }" )
234
+
235
+ end
236
+
237
+ }
238
+
239
+ end
240
+
241
+ def self.parent_test_object_element( test_object )
242
+
243
+ # retrieve parent of current xml element; objects/object/objects/object/../..
244
+ test_object.xml_data.parent.parent
245
+
246
+ end
247
+
248
+ # TODO: document me
249
+ def self.test_object_element_attributes( source_data )
250
+
251
+ Hash[
252
+ source_data.attributes.collect{ | key, value |
253
+ [ key.to_s, value.to_s ]
254
+ }
255
+ ]
256
+
257
+ end
258
+
259
+ # TODO: document me
260
+ def self.test_object_element_attribute( source_data, name, &block )
261
+
262
+ result = source_data.attribute( name )
263
+
264
+ unless result
265
+
266
+ if block_given?
267
+
268
+ yield
269
+
270
+ else
271
+
272
+ # raise exception if no such attribute found
273
+ Kernel::raise MobyBase::AttributeNotFoundError.new(
274
+
275
+ "Could not find test object element attribute #{ attribute_name.inspect }"
276
+
277
+ )
278
+
279
+ end
280
+
281
+ else
282
+
283
+ result
284
+
285
+ end
286
+
287
+ end
288
+
289
+ # TODO: document me
290
+ def self.test_object_attribute( source_data, attribute_name, &block )
291
+
292
+ # TODO: consider using at_xpath and adding /value/text() to query string; however "downside" is that if multiple matches found only first value will be returned as result
293
+
294
+ # retrieve attribute(s) from xml
295
+ nodeset = source_data.xpath(
296
+
297
+ "attributes/attribute[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{ attribute_name.downcase }']" # /value/text()"
298
+
299
+ )
300
+
301
+ # if no attributes found call optional code block or raise exception
302
+ if nodeset.empty?
303
+
304
+ if block_given?
305
+
306
+ # pass return value of block as result
307
+ yield
308
+
309
+ else
310
+
311
+ # raise exception if no such attribute found
312
+ Kernel::raise MobyBase::AttributeNotFoundError.new(
313
+
314
+ "Could not find attribute #{ attribute_name.inspect }" # for test object of type #{ type.to_s }"
315
+
316
+ )
317
+
318
+ end
319
+
320
+ else
321
+
322
+ # attribute(s) found
323
+ # Need to disable this for now
324
+ # Kernel::raise MobyBase::MultipleAttributesFoundError.new( "Multiple attributes found with name '%s'" % name ) if nodeset.count > 1
325
+
326
+ # return found attribute
327
+ nodeset.first.content.strip
328
+
329
+ end
330
+
331
+ end
332
+
333
+ # TODO: document me
334
+ def self.test_object_attributes( source_data )
335
+
336
+ # return hash of test object attributes
337
+ Hash[
338
+
339
+ # iterate each attribute and collect name and value
340
+ source_data.xpath( 'attributes/attribute' ).collect{ | test_object |
341
+
342
+ [ test_object.attribute( 'name' ), test_object.at_xpath( 'value/text()' ).to_s ]
343
+
344
+ }
345
+
346
+ ]
347
+
348
+ end
349
+
350
+ # TODO: document me
351
+ def self.application_layout_direction( sut )
352
+
353
+ # temporary fix until testobject will be associated to parent application object
354
+ unless MobyUtil::DynamicAttributeFilter.instance.has_attribute?( 'layoutDirection' )
355
+
356
+ # temporary fix: add 'layoutDirection' to dynamic attributes filtering whitelist...
357
+ MobyUtil::DynamicAttributeFilter.instance.add_attribute( 'layoutDirection' )
358
+
359
+ # temporary fix: ... and refresh sut to retrieve updated xml data
360
+ sut.refresh
361
+
362
+ end
363
+
364
+ # TODO: parent application test object should be passed to get_test_objects; TestObjectAdapter#test_object_attribute( @app.xml_data, 'layoutDirection')
365
+ ( sut.xml_data.at_xpath('*//object[@type="application"]/attributes/attribute[@name="layoutDirection"]/value/text()').content || 'LeftToRight' ).to_s
366
+
367
+ end
368
+
369
+ # TODO: document me
370
+ def self.create_child_accessors!( source_data, test_object )
371
+
372
+ # iterate through each child object type attribute and create accessor method
373
+ source_data.xpath( 'objects/object/@type' ).each{ | object_type |
374
+
375
+ next if object_type.nil?
376
+
377
+ # convert attribute node value to string
378
+ object_type = object_type.content
379
+
380
+ # skip if child accessor is already created
381
+ next if test_object.respond_to?( object_type )
382
+
383
+ # create child accessor method to test object unless already exists
384
+ test_object.instance_eval(
385
+
386
+ "def #{object_type}(rules={}); raise TypeError,'parameter <rules> should be hash' unless rules.kind_of?(Hash); rules[:type]=:#{object_type}; child(rules); end;"
387
+
388
+ ) unless object_type.empty?
389
+
390
+ }
391
+
392
+ end
393
+
394
+ # enable hooking for performance measurement & debug logging
395
+ MobyUtil::Hooking.instance.hook_methods( self ) if defined?( MobyUtil::Hooking )
396
+
397
+ end # TestObjectAdapter
398
+
399
+ end # TDriver