testability-driver 1.1.1 → 1.2.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/config/sut_parameters.rb +21 -8
- data/config/tdriver_custom_error_recovery.rb +83 -0
- data/ext/extconf.rb +3 -2
- data/ext/native_extensions.c +60 -2
- data/lib/tdriver-devtools/behaviour/old/xml/example/flick-example.rb +2 -105
- data/lib/tdriver/base/behaviour/factory.rb +154 -89
- data/lib/tdriver/base/behaviour/factory_new.rb +409 -0
- data/lib/tdriver/base/errors.rb +3 -3
- data/lib/tdriver/base/state_object.rb +85 -22
- data/lib/tdriver/base/sut/adapter.rb +26 -0
- data/lib/tdriver/base/sut/controller.rb +1 -1
- data/lib/tdriver/base/sut/generic/behaviours/application.rb +89 -118
- data/lib/tdriver/base/sut/generic/behaviours/find.rb +67 -62
- data/lib/tdriver/base/sut/generic/behaviours/sut.rb +296 -187
- data/lib/tdriver/base/sut/generic/behaviours/switchbox_behaviour.rb +7 -7
- data/lib/tdriver/base/sut/generic/commands/application.rb +366 -295
- data/lib/tdriver/base/sut/sut.rb +19 -3
- data/lib/tdriver/base/test_object/abstract.rb +41 -21
- data/lib/tdriver/base/test_object/adapter.rb +62 -9
- data/lib/tdriver/base/test_object/behaviours/syncronization.rb +10 -6
- data/lib/tdriver/base/test_object/behaviours/test_object.rb +84 -47
- data/lib/tdriver/base/test_object/factory.rb +124 -68
- data/lib/tdriver/base/test_object/loader.rb +3 -4
- data/lib/tdriver/base/test_object/verification.rb +3 -3
- data/lib/tdriver/base/test_object/xml/adapter.rb +734 -0
- data/lib/tdriver/loader.rb +12 -0
- data/lib/tdriver/report/error_recovery/tdriver_error_recovery.rb +3 -2
- data/lib/tdriver/report/error_recovery/tdriver_error_recovery_settings.rb +14 -14
- data/lib/tdriver/report/report.rb +4 -8
- data/lib/tdriver/report/report_api.rb +9 -0
- data/lib/tdriver/report/report_crash_file_capture.rb +4 -4
- data/lib/tdriver/report/report_creator.rb +57 -35
- data/lib/tdriver/report/report_cucumber.rb +1 -1
- data/lib/tdriver/report/report_cucumber_listener.rb +5 -158
- data/lib/tdriver/report/report_cucumber_reporter.rb +7 -161
- data/lib/tdriver/report/report_execution_statistics.rb +4 -4
- data/lib/tdriver/report/report_file_capture.rb +5 -5
- data/lib/tdriver/report/report_grouping.rb +24 -22
- data/lib/tdriver/report/report_junit_xml.rb +5 -5
- data/lib/tdriver/report/report_test_case_run.rb +31 -22
- data/lib/tdriver/report/report_test_run.rb +107 -104
- data/lib/tdriver/report/report_writer.rb +150 -83
- data/lib/tdriver/tdriver.rb +147 -103
- data/lib/tdriver/util/common/boolean.rb +51 -0
- data/lib/tdriver/util/common/crc16.rb +110 -68
- data/lib/tdriver/util/common/hash.rb +63 -7
- data/lib/tdriver/util/common/kernel.rb +46 -1
- data/lib/tdriver/util/common/loader.rb +1 -0
- data/lib/tdriver/util/common/object.rb +20 -8
- data/lib/tdriver/util/common/string.rb +21 -2
- data/lib/tdriver/util/logger/logger.rb +4 -4
- data/lib/tdriver/util/parameter/loader.rb +2 -19
- data/lib/tdriver/util/parameter/parameter.rb +874 -177
- data/lib/tdriver/util/plugin/service.rb +1 -1
- data/lib/tdriver/util/recorder/recorder.rb +7 -1
- data/lib/tdriver/util/xml/abstraction.rb +13 -1
- data/lib/tdriver/util/xml/parsers/nokogiri/abstraction.rb +63 -10
- data/lib/tdriver/util/xml/parsers/nokogiri/attribute.rb +8 -2
- data/lib/tdriver/util/xml/parsers/nokogiri/document.rb +16 -3
- data/lib/tdriver/util/xml/parsers/nokogiri/node.rb +36 -32
- data/lib/tdriver/util/xml/parsers/nokogiri/nodeset.rb +19 -22
- data/lib/tdriver/util/xml/xml.rb +147 -32
- data/lib/tdriver/verify/verify.rb +1112 -289
- data/lib/tdriver/version.rb +1 -1
- data/xml/templates/generic.xml +14 -2
- metadata +51 -24
- data/lib/tdriver/util/parameter/parameter_hash.rb +0 -104
- data/lib/tdriver/util/parameter/parameter_new.rb +0 -869
- data/lib/tdriver/util/parameter/parameter_template.rb +0 -120
- data/lib/tdriver/util/parameter/parameter_user_api.rb +0 -116
- data/lib/tdriver/util/parameter/parameter_xml.rb +0 -261
@@ -27,10 +27,10 @@ module MobyBase
|
|
27
27
|
|
28
28
|
include Singleton
|
29
29
|
|
30
|
-
attr_reader :timeout
|
30
|
+
attr_reader :timeout, :test_object_adapter
|
31
31
|
|
32
32
|
# TODO: Document me (TestObjectFactory::initialize)
|
33
|
-
def initialize
|
33
|
+
def initialize( options = {} )
|
34
34
|
|
35
35
|
# get timeout from parameters, use default value if parameter not found
|
36
36
|
@timeout = $parameters[ :application_synchronization_timeout, "20" ].to_f
|
@@ -38,6 +38,8 @@ module MobyBase
|
|
38
38
|
# get timeout retry interval from parameters, use default value if parameter not found
|
39
39
|
@_retry_interval = $parameters[ :application_synchronization_retry_interval, "1" ].to_f
|
40
40
|
|
41
|
+
#@test_object_adapter = TDriver::TestObjectAdapter
|
42
|
+
|
41
43
|
end
|
42
44
|
|
43
45
|
# Function to set timeout for TestObjectFactory
|
@@ -65,6 +67,9 @@ module MobyBase
|
|
65
67
|
# retrieve sut object
|
66
68
|
sut = rules[ :parent ].instance_variable_get( :@sut )
|
67
69
|
|
70
|
+
# retrieve sut objects test object adapter
|
71
|
+
test_object_adapter = sut.instance_variable_get( :@test_object_adapter )
|
72
|
+
|
68
73
|
# search parameters for find_objects feature
|
69
74
|
search_parameters = make_object_search_params( rules[ :parent ], rules[ :object_attributes_hash ] )
|
70
75
|
|
@@ -90,10 +95,12 @@ module MobyBase
|
|
90
95
|
:__xy_sorting => directives.has_key?( :__index ),
|
91
96
|
|
92
97
|
# determine index of test object to be retrieved
|
93
|
-
:__index => 0
|
94
|
-
|
98
|
+
:__index => 0,
|
99
|
+
|
100
|
+
:__retriable_allowed_exceptions => [ MobyBase::TestObjectNotFoundError, MobyBase::MultipleTestObjectsIdentifiedError ]
|
101
|
+
|
95
102
|
)
|
96
|
-
|
103
|
+
|
97
104
|
# identify objects until desired matches found or timeout exceeds
|
98
105
|
MobyUtil::Retryable.until(
|
99
106
|
|
@@ -104,15 +111,18 @@ module MobyBase
|
|
104
111
|
:interval => directives[ :__retry_interval ],
|
105
112
|
|
106
113
|
# following exceptions are allowed; Retry until timeout exceeds or other exception type is raised
|
107
|
-
:exception => [
|
108
|
-
|
114
|
+
:exception => directives[ :__retriable_allowed_exceptions ]
|
115
|
+
|
109
116
|
){
|
110
117
|
|
111
118
|
# refresh sut
|
112
119
|
sut.refresh( directives[ :__refresh_arguments ], search_parameters )
|
113
120
|
|
121
|
+
# in case of test object adapter was change during the refresh (if connected the SUT first time, see possible 'connect_after' hook from sut plugin)
|
122
|
+
test_object_adapter = sut.instance_variable_get( :@test_object_adapter )
|
123
|
+
|
114
124
|
# retrieve objects from xml
|
115
|
-
matches, rule =
|
125
|
+
matches, rule = test_object_adapter.get_objects(
|
116
126
|
|
117
127
|
rules[ :parent ].xml_data,
|
118
128
|
rules[ :object_attributes_hash ],
|
@@ -120,14 +130,40 @@ module MobyBase
|
|
120
130
|
|
121
131
|
)
|
122
132
|
|
133
|
+
# Temporary prevent users misleading :Text with :text (as they are different)
|
134
|
+
if ( rules[ :object_attributes_hash ].has_key?(:Text) )
|
135
|
+
|
136
|
+
rules[ :object_attributes_hash ][:text] = rules[ :object_attributes_hash ][:Text]
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
# If retrying and regexp search is turned on then update the rules for text search converting it to a regex
|
141
|
+
if (
|
142
|
+
matches.empty? and
|
143
|
+
$parameters[ sut.id ][:elided_search, 'false'] == 'true' and
|
144
|
+
rules[ :object_attributes_hash ].has_key?(:text) and
|
145
|
+
rules[ :object_attributes_hash ][ :text ].kind_of? String
|
146
|
+
)
|
147
|
+
text_string = rules[ :object_attributes_hash ][ :text ]
|
148
|
+
if ( $parameters[ sut.id ][:elided_search_with_ellipsis , 'false'] == 'true' )
|
149
|
+
ellipsis_char = ".*\xE2\x80\xA6" # unicode \u2026 the ... character \xE2\x80\xA6
|
150
|
+
else
|
151
|
+
ellipsis_char = ""
|
152
|
+
end
|
153
|
+
elided_regex = Regexp.new( text_string[0..3] + ellipsis_char )
|
154
|
+
rules[ :object_attributes_hash ][ :text ] = elided_regex
|
155
|
+
end
|
156
|
+
|
123
157
|
# raise exception if no matching object(s) found
|
124
158
|
raise MobyBase::TestObjectNotFoundError, "Cannot find object with rule:\n#{ rules[ :object_attributes_hash ].inspect }" if matches.empty?
|
125
159
|
|
126
160
|
# raise exception if multiple matches found and only one expected
|
127
161
|
if ( !directives[ :__multiple_objects ] ) && ( matches.count > 1 && !directives[ :__index_given ] )
|
128
162
|
|
163
|
+
message = "Multiple test objects found with rule: #{ rules[ :object_attributes_hash ].inspect }\nMatching objects:\n#{ list_matching_test_objects_as_list( test_object_adapter, matches ) }\n"
|
164
|
+
|
129
165
|
# raise exception (with list of paths to all matching objects) if multiple objects flag is false and more than one match found
|
130
|
-
raise MobyBase::MultipleTestObjectsIdentifiedError,
|
166
|
+
raise MobyBase::MultipleTestObjectsIdentifiedError, message
|
131
167
|
|
132
168
|
end
|
133
169
|
|
@@ -135,9 +171,9 @@ module MobyBase
|
|
135
171
|
if directives[ :__xy_sorting ] == true
|
136
172
|
|
137
173
|
# sort elements
|
138
|
-
|
174
|
+
test_object_adapter.sort_elements(
|
139
175
|
matches,
|
140
|
-
|
176
|
+
test_object_adapter.application_layout_direction( sut )
|
141
177
|
)
|
142
178
|
|
143
179
|
end
|
@@ -162,6 +198,12 @@ module MobyBase
|
|
162
198
|
# TODO: document me
|
163
199
|
def get_test_objects( rules )
|
164
200
|
|
201
|
+
# retrieve sut object
|
202
|
+
sut = rules[ :parent ].instance_variable_get( :@sut )
|
203
|
+
|
204
|
+
# retrieve sut objects test object adapter
|
205
|
+
test_object_adapter = sut.instance_variable_get( :@test_object_adapter )
|
206
|
+
|
165
207
|
# store rules hash to variable
|
166
208
|
object_attributes_hash = rules[ :object_attributes_hash ].clone
|
167
209
|
|
@@ -243,29 +285,29 @@ module MobyBase
|
|
243
285
|
MobyUtil::DynamicAttributeFilter.instance.add_attributes( object_attributes_hash.keys )
|
244
286
|
|
245
287
|
child_objects = identify_object( rules ).collect{ | test_object_xml |
|
288
|
+
|
289
|
+
# in case of test object adapter was change during the refresh (if connected the SUT first time, see possible 'connect_after' hook from sut plugin)
|
290
|
+
test_object_adapter = sut.instance_variable_get( :@test_object_adapter )
|
246
291
|
|
247
292
|
# create parent application test object if none defined in rules; most likely the call is originated from SUT#child, but not by using SUT#application
|
248
293
|
unless identification_directives.has_key?( :__parent_application ) || rules.has_key?( :parent_application )
|
249
294
|
|
250
295
|
# retrieve application test object xml element
|
251
|
-
application_test_object_xml =
|
296
|
+
application_test_object_xml = test_object_adapter.retrieve_parent_application( test_object_xml )
|
252
297
|
|
253
298
|
unless application_test_object_xml.nil?
|
254
299
|
|
255
|
-
# retrieve sut object
|
256
|
-
sut = rules[ :parent ].instance_variable_get( :@sut )
|
257
|
-
|
258
300
|
# retrieve test object id from xml
|
259
|
-
object_id =
|
301
|
+
object_id = test_object_adapter.test_object_element_attribute( application_test_object_xml, 'id', nil ).to_i
|
260
302
|
|
261
303
|
# retrieve test object name from xml
|
262
|
-
object_name =
|
304
|
+
object_name = test_object_adapter.test_object_element_attribute( application_test_object_xml, 'name', nil ).to_s
|
263
305
|
|
264
306
|
# retrieve test object type from xml
|
265
|
-
object_type =
|
307
|
+
object_type = test_object_adapter.test_object_element_attribute( application_test_object_xml, 'type', nil ).to_s
|
266
308
|
|
267
309
|
# calculate object cache hash key
|
268
|
-
hash_key =
|
310
|
+
hash_key = test_object_adapter.test_object_hash( object_id, object_type, object_name )
|
269
311
|
|
270
312
|
parent_cache = sut.instance_variable_get( :@child_object_cache )
|
271
313
|
|
@@ -281,8 +323,11 @@ module MobyBase
|
|
281
323
|
|
282
324
|
:parent => sut,
|
283
325
|
:parent_application => nil,
|
284
|
-
:xml_object => application_test_object_xml
|
285
|
-
|
326
|
+
:xml_object => application_test_object_xml,
|
327
|
+
|
328
|
+
# object identification attributes
|
329
|
+
:object_attributes_hash => { :name => object_name, :type => object_type }
|
330
|
+
|
286
331
|
)
|
287
332
|
|
288
333
|
end
|
@@ -312,7 +357,9 @@ module MobyBase
|
|
312
357
|
:xml_object => test_object_xml,
|
313
358
|
|
314
359
|
# object identification attributes
|
315
|
-
:object_attributes_hash => object_attributes_hash
|
360
|
+
:object_attributes_hash => object_attributes_hash,
|
361
|
+
|
362
|
+
:identification_directives => identification_directives
|
316
363
|
|
317
364
|
)
|
318
365
|
|
@@ -325,32 +372,43 @@ module MobyBase
|
|
325
372
|
|
326
373
|
# TODO: document me
|
327
374
|
def make_test_object( rules )
|
328
|
-
|
375
|
+
|
329
376
|
# get parent object from hash
|
330
377
|
parent = rules[ :parent ]
|
331
378
|
|
332
379
|
# retrieve sut object
|
333
380
|
sut = parent.instance_variable_get( :@sut )
|
381
|
+
|
382
|
+
# retrieve sut objects test object adapter
|
383
|
+
#test_object_adapter = sut.instance_variable_get( :@sut_controller ).test_object_adapter
|
384
|
+
test_object_adapter = sut.instance_variable_get( :@test_object_adapter )
|
385
|
+
|
386
|
+
# retrieve sut objects test object factory
|
387
|
+
#test_object_factory = sut.instance_variable_get( :@sut_controller ).test_object_factory
|
388
|
+
test_object_factory = sut.instance_variable_get( :@test_object_factory )
|
334
389
|
|
335
390
|
# xml object element
|
336
391
|
xml_object = rules[ :xml_object ]
|
337
392
|
|
393
|
+
# additional rules, e.g. :__no_caching
|
394
|
+
identification_directives = rules[ :identification_directives ] || {}
|
395
|
+
|
338
396
|
# retrieve attributes
|
339
|
-
|
397
|
+
#@test_object_adapter.fetch_attributes( xml_object, [ 'id', 'name', 'type', 'env' ], false )
|
340
398
|
|
341
399
|
if xml_object.kind_of?( MobyUtil::XML::Element )
|
342
400
|
|
343
401
|
# retrieve test object id from xml
|
344
|
-
object_id =
|
402
|
+
object_id = test_object_adapter.test_object_element_attribute( xml_object, 'id', nil ).to_i
|
345
403
|
|
346
404
|
# retrieve test object name from xml
|
347
|
-
object_name =
|
405
|
+
object_name = test_object_adapter.test_object_element_attribute( xml_object, 'name', nil ).to_s
|
348
406
|
|
349
407
|
# retrieve test object type from xml
|
350
|
-
object_type =
|
408
|
+
object_type = test_object_adapter.test_object_element_attribute( xml_object, 'type', nil ).to_s
|
351
409
|
|
352
410
|
# retrieve test object type from xml
|
353
|
-
env =
|
411
|
+
env = test_object_adapter.test_object_element_attribute( xml_object, 'env' ){ $parameters[ sut.id ][ :env ] }.to_s
|
354
412
|
|
355
413
|
else
|
356
414
|
|
@@ -366,7 +424,7 @@ module MobyBase
|
|
366
424
|
end
|
367
425
|
|
368
426
|
# calculate object cache hash key
|
369
|
-
hash_key =
|
427
|
+
hash_key = test_object_adapter.test_object_hash( object_id, object_type, object_name )
|
370
428
|
|
371
429
|
# get reference to parent objects child objects cache
|
372
430
|
parent_cache = rules[ :parent ].instance_variable_get( :@child_object_cache )
|
@@ -380,45 +438,55 @@ module MobyBase
|
|
380
438
|
# store xml_object to test object
|
381
439
|
test_object.xml_data = xml_object
|
382
440
|
|
441
|
+
# update test objects creation attributes (either cached object or just newly created child object)
|
442
|
+
test_object.instance_variable_get( :@creation_attributes ).merge!( rules[ :object_attributes_hash ] )
|
443
|
+
|
383
444
|
else
|
384
445
|
|
385
446
|
# create test object
|
386
|
-
test_object = MobyBase::TestObject.new(
|
447
|
+
test_object = MobyBase::TestObject.new(
|
448
|
+
|
449
|
+
:test_object_factory => test_object_factory, #self,
|
450
|
+
:test_object_adapter => test_object_adapter, #@test_object_adapter,
|
451
|
+
:creation_attributes => rules[ :object_attributes_hash ],
|
452
|
+
:xml_object => xml_object,
|
453
|
+
:sut => sut,
|
454
|
+
|
455
|
+
# set given parent in rules hash as parent object for new child test object
|
456
|
+
:parent => parent,
|
387
457
|
|
388
|
-
|
458
|
+
# set given application test object in rules hash as parent application for new child test object
|
459
|
+
:parent_application => rules[ :parent_application ]
|
460
|
+
|
461
|
+
)
|
462
|
+
|
463
|
+
# temp. variable for object type
|
464
|
+
obj_type = object_type.clone
|
389
465
|
|
390
466
|
# apply all test object related behaviours unless object type is 'application'
|
391
|
-
|
467
|
+
obj_type << ';*' unless obj_type == 'application'
|
392
468
|
|
393
469
|
# apply behaviours to test object
|
394
470
|
MobyBase::BehaviourFactory.instance.apply_behaviour!(
|
395
471
|
|
396
472
|
:object => test_object,
|
397
|
-
:object_type => [ *
|
473
|
+
:object_type => [ *obj_type.split(';') ],
|
398
474
|
:input_type => [ '*', sut.input.to_s ],
|
399
475
|
:env => [ '*', *env.to_s.split(";") ],
|
400
476
|
:version => [ '*', sut.ui_version.to_s ]
|
401
477
|
|
402
478
|
)
|
403
|
-
# create child accessors
|
404
|
-
TDriver::TestObjectAdapter.create_child_accessors!( xml_object, test_object )
|
405
|
-
|
406
|
-
# set given parent in rules hash as parent object for new child test object
|
407
|
-
test_object.instance_variable_set( :@parent, parent )
|
408
479
|
|
409
|
-
#
|
410
|
-
|
480
|
+
# create child accessors
|
481
|
+
test_object_adapter.create_child_accessors!( xml_object, test_object )
|
411
482
|
|
412
|
-
# add created test object to parents child objects cache
|
413
|
-
parent_cache.add_object( test_object )
|
483
|
+
# add created test object to parents child objects cache, unless explicitly disabled
|
484
|
+
parent_cache.add_object( test_object ) unless identification_directives[ :__no_caching ] == true
|
414
485
|
|
415
486
|
end
|
416
487
|
|
417
488
|
# NOTE: Do not remove object_type from object attributes hash_rule due to it is used in find_objects service!
|
418
489
|
#rules[ :object_attributes_hash ].delete( :type )
|
419
|
-
|
420
|
-
# update test objects creation attributes (either cached object or just newly created child object)
|
421
|
-
test_object.instance_variable_set( :@creation_attributes, rules[ :object_attributes_hash ] )
|
422
490
|
|
423
491
|
# do not make test object verifications if we are operating on the sut itself (allow run to pass)
|
424
492
|
unless parent.kind_of?( MobyBase::SUT )
|
@@ -453,8 +521,12 @@ module MobyBase
|
|
453
521
|
|
454
522
|
object_search_params = creation_attributes.clone
|
455
523
|
|
456
|
-
|
457
|
-
object_search_params[ :
|
524
|
+
# see below lines how to do following easier
|
525
|
+
#object_search_params[ :className ] = object_search_params.delete( :type ) if creation_attributes.has_key?( :type )
|
526
|
+
#object_search_params[ :objectName ] = object_search_params.delete( :name ) if creation_attributes.has_key?( :name )
|
527
|
+
|
528
|
+
object_search_params.rename_key!( :type, :className ){}
|
529
|
+
object_search_params.rename_key!( :name, :objectName ){}
|
458
530
|
|
459
531
|
object_search_params
|
460
532
|
|
@@ -487,31 +559,15 @@ module MobyBase
|
|
487
559
|
end
|
488
560
|
|
489
561
|
# TODO: document me
|
490
|
-
def
|
562
|
+
def list_matching_test_objects_as_list( test_object_adapter, matches )
|
491
563
|
|
492
|
-
matches.collect{ | object |
|
493
|
-
|
494
|
-
path = [ object.attribute( 'type' ) ]
|
564
|
+
test_object_adapter.list_test_objects_as_string( matches ).each_with_index.collect{ | object, object_index |
|
495
565
|
|
496
|
-
|
497
|
-
|
498
|
-
# object/objects/object/../..
|
499
|
-
object = object.parent.parent
|
500
|
-
|
501
|
-
path << object.attribute( 'type' )
|
502
|
-
|
503
|
-
end
|
504
|
-
|
505
|
-
path.reverse.join( '.' )
|
506
|
-
|
507
|
-
}.sort
|
508
|
-
|
509
|
-
end
|
566
|
+
"%3s) %s" % [ object_index + 1, object ]
|
510
567
|
|
511
|
-
|
512
|
-
def list_matching_test_objects_as_list( matches )
|
568
|
+
}.join( "\n" )
|
513
569
|
|
514
|
-
list_matching_test_objects( matches ).each_with_index.collect{ | object, object_index | "%3s) %s" % [ object_index + 1, object ] }.join( "\n" )
|
570
|
+
#list_matching_test_objects( matches ).each_with_index.collect{ | object, object_index | "%3s) %s" % [ object_index + 1, object ] }.join( "\n" )
|
515
571
|
|
516
572
|
end
|
517
573
|
|
@@ -32,12 +32,11 @@ require File.expand_path( File.join( File.dirname( __FILE__ ), 'cache' ) )
|
|
32
32
|
# load test object adapter
|
33
33
|
require File.expand_path( File.join( File.dirname( __FILE__ ), 'adapter' ) )
|
34
34
|
|
35
|
+
# load test object adapter
|
36
|
+
require File.expand_path( File.join( File.dirname( __FILE__ ), 'xml/adapter' ) )
|
37
|
+
|
35
38
|
# load verify ui module
|
36
39
|
require File.expand_path( File.join( File.dirname( __FILE__ ), 'verification' ) )
|
37
40
|
|
38
41
|
# load test object behaviours
|
39
42
|
MobyUtil::FileHelper.load_modules( File.expand_path( File.join( File.dirname( __FILE__ ), 'behaviours' ) ) )
|
40
|
-
|
41
|
-
# load report api for continous verification reporting purposes
|
42
|
-
require File.expand_path( File.join( File.dirname( __FILE__ ), '../../report/report_api' ) ) if MobyUtil::Parameter[ :report_attach_continuous_verification_to_reporter, nil ]=='true'
|
43
|
-
|
@@ -104,7 +104,7 @@ module TDriver
|
|
104
104
|
TDriverReportAPI::tdriver_report_log("<hr />")
|
105
105
|
|
106
106
|
$logger.enabled = logging_enabled
|
107
|
-
$logger.
|
107
|
+
$logger.behaviour "FAIL;Verification #{verify.message.nil? ? '' : '\"' << verify.message << '\" '}failed:#{e.to_s}.\n#{verify.timeout.nil? ? '' : ' using timeout ' + verify.timeout.to_s}.;#{sut.id.to_s+';sut'};{};verify_always;" << verify.expected.to_s
|
108
108
|
|
109
109
|
end
|
110
110
|
|
@@ -144,7 +144,7 @@ module TDriver
|
|
144
144
|
|
145
145
|
$logger.enabled = logging_enabled
|
146
146
|
|
147
|
-
$logger.
|
147
|
+
$logger.behaviour "FAIL;Verification #{verify.message.nil? ? '' : '\"' << verify.message << '\" '}failed:#{e.to_s}.\n#{verify.timeout.nil? ? '' : ' using timeout ' + verify.timeout.to_s}.;#{sut.id.to_s+';sut'};{};verify_always;" << verify.expected.to_s
|
148
148
|
|
149
149
|
end
|
150
150
|
|
@@ -154,7 +154,7 @@ module TDriver
|
|
154
154
|
|
155
155
|
$logger.enabled = logging_enabled
|
156
156
|
|
157
|
-
$logger.
|
157
|
+
$logger.behaviour "FAIL;Verification #{verify.message.nil? ? '' : '\"' << verify.message << '\" '}failed:#{e.to_s}.\n#{verify.timeout.nil? ? '' : ' using timeout ' + verify.timeout.to_s}.;#{sut.id.to_s+';sut'};{};verify_always;" << verify.expected.to_s
|
158
158
|
|
159
159
|
@@inside_verify = false
|
160
160
|
|
@@ -0,0 +1,734 @@
|
|
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
|
+
module OptimizedXML
|
23
|
+
|
24
|
+
class TestObjectAdapter
|
25
|
+
|
26
|
+
# private methods and variables
|
27
|
+
class << self
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# TODO: document me
|
32
|
+
def xpath_attributes( attributes, element_attributes, object_type )
|
33
|
+
|
34
|
+
# collect attributes
|
35
|
+
attributes = attributes.collect{ | key, values |
|
36
|
+
|
37
|
+
# allow multiple values options for attribute, e.g. object which 'text' attribute value is either '1' or '2'
|
38
|
+
( values.kind_of?( Array ) ? values : [ values ] ).collect{ | value |
|
39
|
+
|
40
|
+
# concatenate string if it contains single and double quotes, otherwise return as is
|
41
|
+
value = xpath_literal_string( value )
|
42
|
+
|
43
|
+
prefix_key = "@#{ key }"
|
44
|
+
|
45
|
+
if @partial_match_allowed.include?( [ object_type, key ] )
|
46
|
+
|
47
|
+
# regexp support is needed also here
|
48
|
+
|
49
|
+
prefix_value = "[contains(.,#{ value })]"
|
50
|
+
attribute_value = "contains(.,#{ value })"
|
51
|
+
|
52
|
+
else
|
53
|
+
|
54
|
+
if value.kind_of?( Regexp )
|
55
|
+
|
56
|
+
prefix_value = "regexp_compare(#{ prefix_key },'#{ value.source }',#{ value.options })"
|
57
|
+
attribute_value = "regexp_compare(.,'#{ value.source }',#{ value.options })"
|
58
|
+
|
59
|
+
prefix_key = ""
|
60
|
+
|
61
|
+
else
|
62
|
+
|
63
|
+
#prefix_value = "=#{ value }"
|
64
|
+
#attribute_value = "text()=#{ value }"
|
65
|
+
|
66
|
+
prefix_value = "=#{ value }"
|
67
|
+
attribute_value = ".=#{ value }"
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
# construct xpath
|
74
|
+
#"(#{ element_attributes ? "#{ prefix_key }#{ prefix_value } or " : "" }attr[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{ key }' and #{ attribute_value }])"
|
75
|
+
"(#{ element_attributes ? "#{ prefix_key }#{ prefix_value } or " : "" }attr[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{ key }' and #{ attribute_value }])"
|
76
|
+
|
77
|
+
}.join( ' or ' ) # join attribute alternative values
|
78
|
+
|
79
|
+
}.join( ' and ' ) # join all required attributes
|
80
|
+
|
81
|
+
#p attributes
|
82
|
+
|
83
|
+
# return created xpath or nil if no attributes given
|
84
|
+
if attributes.empty?
|
85
|
+
|
86
|
+
# no attributes given
|
87
|
+
nil
|
88
|
+
|
89
|
+
else
|
90
|
+
|
91
|
+
# return result
|
92
|
+
attributes
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end # xpath_attributes
|
97
|
+
|
98
|
+
# TODO: document me
|
99
|
+
def initialize_class
|
100
|
+
|
101
|
+
# special cases: allow partial match when value of type and attribute name matches
|
102
|
+
@partial_match_allowed = [ 'list_item', 'text' ], [ 'application', 'fullname' ]
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end # static
|
107
|
+
|
108
|
+
# TODO: document me
|
109
|
+
def self.regexp_compare( nodeset, source, options )
|
110
|
+
|
111
|
+
# rebuild defined regexp, used while matching element content
|
112
|
+
regexp_object = Regexp.new( source.to_s, options.to_i )
|
113
|
+
|
114
|
+
# collect all nodes matching with regexp
|
115
|
+
nodeset.find_all{ | node | node.content =~ regexp_object }
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
# TODO: document me
|
120
|
+
def self.xpath_to_object( rules, find_all_children )
|
121
|
+
|
122
|
+
# convert hash keys to downcased string
|
123
|
+
rules = Hash[
|
124
|
+
|
125
|
+
rules.collect{ | key, value |
|
126
|
+
|
127
|
+
case value
|
128
|
+
|
129
|
+
# pass the value as is if type of regexp or array; array is used in localisation cases e.g. [ 'one', 'yksi', 'uno' ] # etc
|
130
|
+
when Regexp, Array
|
131
|
+
|
132
|
+
[ key.to_s.downcase, value ]
|
133
|
+
|
134
|
+
else
|
135
|
+
|
136
|
+
[ key.to_s.downcase, value.to_s ]
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
}
|
141
|
+
|
142
|
+
]
|
143
|
+
|
144
|
+
# xpath container array
|
145
|
+
test_object_xpath_array = []
|
146
|
+
|
147
|
+
# store and remove object element attributes from hash
|
148
|
+
object_element_attributes = rules.delete_keys!( 'name', 'type', 'parent', 'id' )
|
149
|
+
|
150
|
+
# children method may request test objects of any type
|
151
|
+
if object_element_attributes[ 'type' ] == '*'
|
152
|
+
|
153
|
+
# test object with any name, type, parent and id is allowed
|
154
|
+
test_object_xpath_array << '@*'
|
155
|
+
|
156
|
+
else
|
157
|
+
|
158
|
+
# required attributes
|
159
|
+
test_object_xpath_array << xpath_attributes( object_element_attributes, true, object_element_attributes[ 'type' ] )
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
# additional attributes, eg. :text, :x, :y etc.
|
164
|
+
test_object_xpath_array << xpath_attributes( rules, false, object_element_attributes[ 'type' ] )
|
165
|
+
|
166
|
+
# join required and additional attribute strings
|
167
|
+
test_object_xpath_string = test_object_xpath_array.compact.join( ' and ' )
|
168
|
+
|
169
|
+
# return any child element under current node or only immediate child element
|
170
|
+
#find_all_children ? "*//obj[#{ test_object_xpath_string }]" : "obj[1]/obj[#{ test_object_xpath_string }]"
|
171
|
+
|
172
|
+
find_all_children ? ".//obj[#{ test_object_xpath_string }]" : "obj[#{ test_object_xpath_string }]"
|
173
|
+
|
174
|
+
#"*//obj[#{ test_object_xpath_string }]"
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
# TODO: document me
|
179
|
+
def self.xpath_literal_string( string )
|
180
|
+
|
181
|
+
return string if string.kind_of?( Regexp )
|
182
|
+
|
183
|
+
# make sure that argument is type of string
|
184
|
+
string = string.to_s
|
185
|
+
|
186
|
+
# does not contain no single quotes
|
187
|
+
if not string.include?("'")
|
188
|
+
|
189
|
+
result = "'#{ string }'"
|
190
|
+
|
191
|
+
# does not contain no double quotes
|
192
|
+
elsif not string.include?('"')
|
193
|
+
|
194
|
+
result = "\"#{ string }\""
|
195
|
+
|
196
|
+
# contains single and double quotes
|
197
|
+
else
|
198
|
+
|
199
|
+
# open new item
|
200
|
+
result = ["'"]
|
201
|
+
|
202
|
+
# iterate through each character
|
203
|
+
string.each_char{ | char |
|
204
|
+
|
205
|
+
case char
|
206
|
+
|
207
|
+
# encapsulate single quotes with double quotes
|
208
|
+
when "'"
|
209
|
+
|
210
|
+
# close current item
|
211
|
+
result.last << char
|
212
|
+
|
213
|
+
# add encapsulated single quote
|
214
|
+
result << "\"'\""
|
215
|
+
|
216
|
+
# open new item
|
217
|
+
result << char
|
218
|
+
|
219
|
+
else
|
220
|
+
|
221
|
+
# any other character will appended as is
|
222
|
+
result.last << char
|
223
|
+
|
224
|
+
end
|
225
|
+
|
226
|
+
}
|
227
|
+
|
228
|
+
# close last sentence
|
229
|
+
result.last << "'"
|
230
|
+
|
231
|
+
# create concat clause for xpath
|
232
|
+
result = "concat(#{ result.join(',') })"
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
result
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
# TODO: document me
|
241
|
+
def self.get_objects( source_data, rules, find_all_children )
|
242
|
+
|
243
|
+
rule = xpath_to_object( rules, find_all_children )
|
244
|
+
|
245
|
+
[
|
246
|
+
|
247
|
+
# perform xpath to source xml data
|
248
|
+
source_data.xpath( rule, self ),
|
249
|
+
|
250
|
+
# return also created xpath
|
251
|
+
rule
|
252
|
+
|
253
|
+
]
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
# TODO: document me
|
258
|
+
def self.test_object_hash( object_id, object_type, object_name )
|
259
|
+
|
260
|
+
# calculate test object hash
|
261
|
+
( ( ( 17 * 37 + object_id ) * 37 + object_type.hash ) * 37 + object_name.hash )
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
# Sort XML nodeset of test objects with layout direction
|
266
|
+
def self.sort_elements( nodeset, layout_direction = 'LeftToRight' )
|
267
|
+
|
268
|
+
# cache for x_absolute and y_absolute values; reduces dramatically number of xpath calls
|
269
|
+
cache = {}
|
270
|
+
|
271
|
+
# xpath pattern to be used for x_absolute attribute value
|
272
|
+
x_absolute_pattern = './attr[@name="x_absolute"]/text()'
|
273
|
+
|
274
|
+
# xpath pattern to be used for x_absolute attribute value
|
275
|
+
y_absolute_pattern = './attr[@name="y_absolute"]/text()'
|
276
|
+
|
277
|
+
# collect only nodes that has x_absolute and y_absolute attributes
|
278
|
+
nodeset.collect!{ | node |
|
279
|
+
|
280
|
+
# retrieve x_absolute attribute
|
281
|
+
x_absolute = node.at_xpath( x_absolute_pattern )
|
282
|
+
|
283
|
+
# retrieve y_absolute attribute
|
284
|
+
y_absolute = node.at_xpath( y_absolute_pattern )
|
285
|
+
|
286
|
+
# return unmodified nodeset if both attributes was not found
|
287
|
+
if x_absolute.nil? || y_absolute.nil?
|
288
|
+
|
289
|
+
#warn("Warning: Unable to sort object set due to object type of #{ node.attribute( 'type' ).inspect } does not have \"x_absolute\" or \"y_absolute\" attribute")
|
290
|
+
|
291
|
+
return nodeset
|
292
|
+
|
293
|
+
else
|
294
|
+
|
295
|
+
# store attributes to cache for further processing
|
296
|
+
cache[ node ] = [ x_absolute.content.to_i, y_absolute.content.to_i ]
|
297
|
+
|
298
|
+
# return node as result
|
299
|
+
node
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
}.compact!.sort!{ | element_a, element_b |
|
304
|
+
|
305
|
+
# retrieve element a's attributes x and y
|
306
|
+
element_a_x, element_a_y = cache[ element_a ]
|
307
|
+
|
308
|
+
# retrieve element b's attributes x and y
|
309
|
+
element_b_x, element_b_y = cache[ element_b ]
|
310
|
+
|
311
|
+
case layout_direction
|
312
|
+
|
313
|
+
when 'LeftToRight'
|
314
|
+
|
315
|
+
# compare elements
|
316
|
+
( element_a_y == element_b_y ) ? ( element_a_x <=> element_b_x ) : ( element_a_y <=> element_b_y )
|
317
|
+
|
318
|
+
when 'RightToLeft'
|
319
|
+
|
320
|
+
# compare elements
|
321
|
+
( element_a_y == element_b_y ) ? ( element_b_x <=> element_a_x ) : ( element_a_y <=> element_b_y )
|
322
|
+
|
323
|
+
else
|
324
|
+
|
325
|
+
# raise exception if layout direction it not supported
|
326
|
+
Kernel::raise ArgumentError, "Unsupported layout direction #{ layout_direction.inspect }"
|
327
|
+
|
328
|
+
end
|
329
|
+
|
330
|
+
}
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
def self.parent_test_object_element( test_object )
|
335
|
+
|
336
|
+
# retrieve parent of current xml element; obj/..
|
337
|
+
test_object.xml_data.parent #.parent
|
338
|
+
|
339
|
+
end
|
340
|
+
|
341
|
+
# TODO: document me
|
342
|
+
def self.test_object_element_attributes( source_data )
|
343
|
+
|
344
|
+
Hash[
|
345
|
+
source_data.attributes.collect{ | key, value |
|
346
|
+
[ key.to_s, value.to_s ]
|
347
|
+
}
|
348
|
+
]
|
349
|
+
|
350
|
+
end
|
351
|
+
|
352
|
+
# TODO: document me
|
353
|
+
def self.test_object_element_attribute( source_data, attribute_name, *default, &block )
|
354
|
+
|
355
|
+
result = source_data.attribute( attribute_name )
|
356
|
+
|
357
|
+
# if no attribute found call optional code block or raise exception
|
358
|
+
unless result
|
359
|
+
|
360
|
+
if block_given?
|
361
|
+
|
362
|
+
# pass return value of block as result
|
363
|
+
yield( attribute_name )
|
364
|
+
|
365
|
+
else
|
366
|
+
|
367
|
+
# raise exception if no default value given
|
368
|
+
if default.empty?
|
369
|
+
|
370
|
+
# raise exception if no such attribute found
|
371
|
+
Kernel::raise MobyBase::AttributeNotFoundError, "Could not find test object element attribute #{ attribute_name.inspect }"
|
372
|
+
|
373
|
+
else
|
374
|
+
|
375
|
+
# pass default value as result
|
376
|
+
default.first
|
377
|
+
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|
381
|
+
|
382
|
+
else
|
383
|
+
|
384
|
+
result
|
385
|
+
|
386
|
+
end
|
387
|
+
|
388
|
+
end
|
389
|
+
|
390
|
+
# TODO: document me
|
391
|
+
def self.test_object_attribute( source_data, attribute_name, *default, &block )
|
392
|
+
|
393
|
+
# TODO: consider using at_xpath and adding text() to query string; however "downside" is that if multiple matches found only first value will be returned as result
|
394
|
+
|
395
|
+
# retrieve attribute(s) from xml
|
396
|
+
nodeset = source_data.xpath(
|
397
|
+
|
398
|
+
"attr[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='#{ attribute_name.downcase }']"
|
399
|
+
|
400
|
+
)
|
401
|
+
|
402
|
+
# if no attributes found call optional code block or raise exception
|
403
|
+
if nodeset.empty?
|
404
|
+
|
405
|
+
if block_given?
|
406
|
+
|
407
|
+
# pass return value of block as result
|
408
|
+
yield( attribute_name )
|
409
|
+
|
410
|
+
else
|
411
|
+
|
412
|
+
# raise exception if no default value given
|
413
|
+
if default.empty?
|
414
|
+
|
415
|
+
# raise exception if no such attribute found
|
416
|
+
Kernel::raise MobyBase::AttributeNotFoundError, "Could not find attribute #{ attribute_name.inspect }" # for test object of type #{ type.to_s }"
|
417
|
+
|
418
|
+
else
|
419
|
+
|
420
|
+
# pass default value as result
|
421
|
+
default.first
|
422
|
+
|
423
|
+
end
|
424
|
+
|
425
|
+
end # block_given?
|
426
|
+
|
427
|
+
else # not nodeset.empty?
|
428
|
+
|
429
|
+
# attribute(s) found
|
430
|
+
# Need to disable this for now
|
431
|
+
# Kernel::raise MobyBase::MultipleAttributesFoundError.new( "Multiple attributes found with name '%s'" % name ) if nodeset.count > 1
|
432
|
+
|
433
|
+
# return found attribute
|
434
|
+
nodeset.first.content
|
435
|
+
|
436
|
+
end
|
437
|
+
|
438
|
+
end
|
439
|
+
|
440
|
+
# TODO: document me
|
441
|
+
def self.test_object_attributes( source_data, inclusive_filter = [] )
|
442
|
+
|
443
|
+
# convert all keys to lowercase
|
444
|
+
inclusive_filter.collect!{ | key | key.to_s.downcase } unless inclusive_filter.empty?
|
445
|
+
|
446
|
+
# return hash of test object attributes
|
447
|
+
Hash[
|
448
|
+
|
449
|
+
# iterate each attribute and collect name and value
|
450
|
+
source_data.xpath( 'attr' ).collect{ | value |
|
451
|
+
|
452
|
+
# retrieve attribute name
|
453
|
+
name = value.attribute('name').to_s
|
454
|
+
|
455
|
+
# collect attribute elements name and content
|
456
|
+
unless inclusive_filter.empty?
|
457
|
+
|
458
|
+
[ name, value.content ] if inclusive_filter.include?( name.downcase )
|
459
|
+
|
460
|
+
else
|
461
|
+
|
462
|
+
# pass the attribute pair - no filtering done
|
463
|
+
[ name, value.content ]
|
464
|
+
|
465
|
+
end
|
466
|
+
|
467
|
+
}
|
468
|
+
|
469
|
+
]
|
470
|
+
|
471
|
+
end
|
472
|
+
|
473
|
+
# TODO: document me
|
474
|
+
def self.application_layout_direction( sut )
|
475
|
+
|
476
|
+
# temporary fix until testobject will be associated to parent application object
|
477
|
+
unless MobyUtil::DynamicAttributeFilter.instance.has_attribute?( 'layoutDirection' )
|
478
|
+
|
479
|
+
# temporary fix: add 'layoutDirection' to dynamic attributes filtering whitelist...
|
480
|
+
MobyUtil::DynamicAttributeFilter.instance.add_attribute( 'layoutDirection' )
|
481
|
+
|
482
|
+
# temporary fix: ... and refresh sut to retrieve updated xml data
|
483
|
+
sut.refresh
|
484
|
+
|
485
|
+
end
|
486
|
+
|
487
|
+
# TODO: parent application test object should be passed to get_test_objects; TestObjectAdapter#test_object_attribute( @app.xml_data, 'layoutDirection')
|
488
|
+
#( sut.xml_data.at_xpath('*//obj[@type="application"]/attr[@name="layoutDirection"]/text()').content || 'LeftToRight' ).to_s
|
489
|
+
|
490
|
+
( sut.xml_data.at_xpath('.//obj[@type="application"]/attr[@name="layoutDirection"]/text()').content || 'LeftToRight' ).to_s
|
491
|
+
|
492
|
+
end
|
493
|
+
|
494
|
+
# TODO: document me
|
495
|
+
def self.create_child_accessors!( source_data, test_object )
|
496
|
+
|
497
|
+
# iterate through each child object type attribute and create accessor method
|
498
|
+
source_data.xpath( 'obj/@type' ).each{ | object_type |
|
499
|
+
|
500
|
+
# skip if object type value is nil or empty due to child accessor cannot be created
|
501
|
+
next if object_type.nil? || object_type.to_s.empty?
|
502
|
+
|
503
|
+
# convert attribute node value to string
|
504
|
+
object_type = object_type.content
|
505
|
+
|
506
|
+
# skip if child accessor is already created
|
507
|
+
next if test_object.respond_to?( object_type )
|
508
|
+
|
509
|
+
begin
|
510
|
+
|
511
|
+
# create child accessor method to test object unless already exists
|
512
|
+
test_object.instance_eval(
|
513
|
+
|
514
|
+
"def #{ object_type }( rules = {} ); raise TypeError,'parameter <rules> should be hash' unless rules.kind_of?( Hash ); rules[ :type ]=:#{ object_type }; child( rules ); end;"
|
515
|
+
|
516
|
+
) unless object_type.empty?
|
517
|
+
|
518
|
+
# in case if object type has some invalid characters, e.g. type is "ns:object"
|
519
|
+
rescue SyntaxError
|
520
|
+
|
521
|
+
warn "warning: unable to create accessor to child test object whose type is #{ object_type.inspect }"
|
522
|
+
|
523
|
+
end
|
524
|
+
|
525
|
+
}
|
526
|
+
|
527
|
+
end
|
528
|
+
|
529
|
+
# TODO: document me
|
530
|
+
def self.state_object_xml( source_data, id )
|
531
|
+
|
532
|
+
# collect each object from source xml
|
533
|
+
objects = source_data.xpath( 'tasInfo/obj' ).collect{ | element | element.to_s }.join
|
534
|
+
|
535
|
+
# return xml root element
|
536
|
+
MobyUtil::XML.parse_string(
|
537
|
+
"<sut name='sut' type='sut' id='#{ id }'>#{ objects }</sut>"
|
538
|
+
).root
|
539
|
+
|
540
|
+
end
|
541
|
+
|
542
|
+
def self.retrieve_parent_application( xml_source )
|
543
|
+
|
544
|
+
xml_source_iterator = xml_source.clone
|
545
|
+
|
546
|
+
while xml_source_iterator.kind_of?( MobyUtil::XML::Element )
|
547
|
+
|
548
|
+
if ( test_object_element_attribute( xml_source_iterator, 'type' ) == 'application' )
|
549
|
+
|
550
|
+
return xml_source_iterator
|
551
|
+
|
552
|
+
end
|
553
|
+
|
554
|
+
if xml_source_iterator.kind_of?( MobyUtil::XML::Element )
|
555
|
+
|
556
|
+
xml_source_iterator = xml_source_iterator.parent
|
557
|
+
|
558
|
+
else
|
559
|
+
|
560
|
+
# not found from xml tree
|
561
|
+
break
|
562
|
+
|
563
|
+
end
|
564
|
+
|
565
|
+
end
|
566
|
+
|
567
|
+
#warn("warning: unable to retrieve parent application")
|
568
|
+
|
569
|
+
raise MobyBase::TestObjectNotFoundError, "Unable to retrieve parent application"
|
570
|
+
|
571
|
+
# return application object or nil if no parent found
|
572
|
+
# Does is make sense to return nil - shouldn't all test objects belong to an application? Maybe throw exception if application not found
|
573
|
+
|
574
|
+
#nil
|
575
|
+
|
576
|
+
#return @sut.child( :type => 'application' ) rescue nil
|
577
|
+
|
578
|
+
end
|
579
|
+
|
580
|
+
# TODO: document me
|
581
|
+
def self.get_xml_element_for_test_object( test_object )
|
582
|
+
|
583
|
+
# retrieve nodeset from sut xml_data
|
584
|
+
nodeset = test_object.instance_variable_get( :@sut ).xml_data.xpath( test_object.instance_variable_get( :@x_path ) )
|
585
|
+
|
586
|
+
# raise exception if no test objects found
|
587
|
+
Kernel::raise MobyBase::TestObjectNotFoundError if nodeset.empty?
|
588
|
+
|
589
|
+
# return first test object from the nodeset
|
590
|
+
nodeset.first
|
591
|
+
|
592
|
+
end
|
593
|
+
|
594
|
+
# TODO: document me
|
595
|
+
def self.get_test_object_identifiers( xml_source, test_object = nil )
|
596
|
+
|
597
|
+
# retrieve parent xpath if test_object given
|
598
|
+
parent_xpath = test_object ? test_object.instance_variable_get( :@parent ).x_path : ""
|
599
|
+
|
600
|
+
# retrieve type attribute
|
601
|
+
type = xml_source.attribute( 'type' )
|
602
|
+
|
603
|
+
# retrieve id attribute
|
604
|
+
id = xml_source.attribute( 'id' )
|
605
|
+
|
606
|
+
# retrieve env attribute
|
607
|
+
env = xml_source.attribute( 'env' )
|
608
|
+
|
609
|
+
# retrieve test object element attributes and return array containting xpath to test object, name, type and id elements
|
610
|
+
[
|
611
|
+
# x_path to test object
|
612
|
+
#test_object ? "#{ parent_xpath }/*//obj[@type='#{ type }' and @id='#{ id }']" : nil,
|
613
|
+
|
614
|
+
test_object ? "#{ parent_xpath }/.//obj[@type='#{ type }' and @id='#{ id }']" : nil,
|
615
|
+
|
616
|
+
# test object name
|
617
|
+
xml_source.attribute( 'name' ),
|
618
|
+
|
619
|
+
# test object type
|
620
|
+
type,
|
621
|
+
|
622
|
+
# test object id
|
623
|
+
id,
|
624
|
+
|
625
|
+
env
|
626
|
+
|
627
|
+
]
|
628
|
+
|
629
|
+
end
|
630
|
+
|
631
|
+
# TODO: document me
|
632
|
+
def self.hash_to_element_attributes( hash )
|
633
|
+
|
634
|
+
hash.collect{ | key, value |
|
635
|
+
|
636
|
+
"#{ key.to_s }=\"#{ value.to_s }\""
|
637
|
+
|
638
|
+
}.join(' ')
|
639
|
+
|
640
|
+
end
|
641
|
+
|
642
|
+
# TODO: document me
|
643
|
+
def self.merge_application_elements( xml_string )
|
644
|
+
|
645
|
+
# parse the ui state xml
|
646
|
+
document_root = MobyUtil::XML.parse_string( xml_string ).root
|
647
|
+
|
648
|
+
# retrieve application objects as nodeset
|
649
|
+
nodeset = document_root.xpath('/tasMessage/tasInfo/obj')
|
650
|
+
|
651
|
+
# check if multiple application objects found
|
652
|
+
if nodeset.count > 1
|
653
|
+
|
654
|
+
# new header, apply original element attributes
|
655
|
+
new_xml = "<tasMessage #{ hash_to_element_attributes( document_root.attributes ) }><tasInfo #{ hash_to_element_attributes( nodeset.first.parent.attributes ) }>"
|
656
|
+
|
657
|
+
# flag defining that is application element already created
|
658
|
+
application_element_set = false
|
659
|
+
|
660
|
+
# collect environment values
|
661
|
+
environments = document_root.xpath('/tasMessage/tasInfo/obj[@type="application"]/@env').collect{ | attribute | attribute.to_s }
|
662
|
+
|
663
|
+
# iterate through each object found in xml
|
664
|
+
nodeset.each{ | object |
|
665
|
+
|
666
|
+
# only one application element
|
667
|
+
unless application_element_set
|
668
|
+
|
669
|
+
#application_objects << object
|
670
|
+
|
671
|
+
# retrieve object attributes
|
672
|
+
attributes = object.attributes
|
673
|
+
|
674
|
+
# merge env to attributes hash
|
675
|
+
attributes['env'] = environments.join(';')
|
676
|
+
|
677
|
+
# add application object xml element to new xml string
|
678
|
+
new_xml << "<obj #{ hash_to_element_attributes( attributes ) }>"
|
679
|
+
|
680
|
+
# application element is now set, no need to do it again
|
681
|
+
application_element_set = true
|
682
|
+
|
683
|
+
end
|
684
|
+
|
685
|
+
# append all found elements
|
686
|
+
object.xpath('./*').each{ | object | new_xml << object.to_s }
|
687
|
+
|
688
|
+
}
|
689
|
+
|
690
|
+
# multiple applications found, return merged application xml
|
691
|
+
new_xml << "</obj></tasInfo></tasMessage>"
|
692
|
+
|
693
|
+
else
|
694
|
+
|
695
|
+
# only one application found, return data as is
|
696
|
+
xml_string
|
697
|
+
|
698
|
+
end
|
699
|
+
|
700
|
+
end
|
701
|
+
|
702
|
+
# TODO: document me
|
703
|
+
def self.list_test_objects_as_string( source_data )
|
704
|
+
|
705
|
+
source_data.collect{ | object |
|
706
|
+
|
707
|
+
path = [ object.attribute( 'type' ) ]
|
708
|
+
|
709
|
+
while object.attribute( 'type' ) != 'application' do
|
710
|
+
|
711
|
+
# object/objects/object/../..
|
712
|
+
object = object.parent
|
713
|
+
|
714
|
+
path << object.attribute( 'type' )
|
715
|
+
|
716
|
+
end
|
717
|
+
|
718
|
+
path.reverse.join( '.' )
|
719
|
+
|
720
|
+
}.sort
|
721
|
+
|
722
|
+
end
|
723
|
+
|
724
|
+
# enable hooking for performance measurement & debug logging
|
725
|
+
TDriver::Hooking.hook_methods( self ) if defined?( TDriver::Hooking )
|
726
|
+
|
727
|
+
# initialize TDriver::TestObjectAdapter
|
728
|
+
initialize_class
|
729
|
+
|
730
|
+
end # TestObjectAdapter
|
731
|
+
|
732
|
+
end # OptimizedXML
|
733
|
+
|
734
|
+
end # TDriver
|