Module: TDriver::TestObjectFactory

Defined in:
lib/tdriver/base/test_object/factory.rb

Class Method Summary collapse

Class Method Details

.get_test_objects(rules) ⇒ Object

TODO: document me



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
# File 'lib/tdriver/base/test_object/factory.rb', line 317

def self.get_test_objects( rules )

  # retrieve sut object
  sut = rules[ :parent ].instance_variable_get( :@sut )

  # retrieve sut objects test object adapter
  test_object_adapter = sut.instance_variable_get( :@test_object_adapter )

  # store rules hash to variable
  object_attributes_hash = rules[ :object_attributes_hash ].clone

  # remove test object identification directives for object identification attributes hash (e.g. :__index, :__multiple_objects etc.)
  identification_directives = rules[ :identification_directives ]
   
  # verify given identification directives, only documented end-user directives is checked
  identification_directives.each{ | key, value |
  
    # do not verify type by default
    type = nil
  
    case key

      # Fixnum          
      when :__index, :__timeout

        # for backward compatibility          
        if value.kind_of?( String )
        
          warn "warning: deprecated variable type String for #{ key.inspect } test object identification directive (expected TrueClass or FalseClass)"          
      
          raise ArgumentError, "deprecated and wrong variable content format for #{ key.inspect } test object identification directive (expected Numeric string)" unless value.numeric?
      
          value = value.to_i
          
        end
      
        type = Fixnum
                
      when :__logging, :__xy_sorting

        # for backward compatibility          
        if value.kind_of?( String )
          
          warn "warning: deprecated variable type String for #{ key.inspect } test object identification directive (expected TrueClass or FalseClass)"          

          value = value.to_boolean 
          
        end
      
        type = [ TrueClass, FalseClass ]
      
    end

    # verify hash value if type defined 
    value.check_type( type, "wrong variable type $1 for #{ key.inspect } test object identification directive (expected $2)" ) unless type.nil?

  }
        
  # do not create refresh arguments hash if already exists
  unless identification_directives.has_key?( :__refresh_arguments )
        
    # create application refresh attributes hash
    if object_attributes_hash[ :type ] == 'application'

      # collect :name, :id and :applicationUid from object_attributes_hash if found
      identification_directives[ :__refresh_arguments ] = object_attributes_hash.collect_keys( :name, :id, :applicationUid )

    else
                        
      if rules[ :parent ].kind_of?( MobyBase::TestObject )

        # get current application for test object
        identification_directives[ :__refresh_arguments ] = { :id => rules[ :parent ].get_application_id }

      elsif rules[ :parent ].kind_of?( MobyBase::SUT )
      
        # get current application for sut
        identification_directives[ :__refresh_arguments ] = { :id => rules[ :parent ].current_application_id }

      end
      
    end

  end
  
  # add object identification attribute keys to dynamic attributes white list
  #TDriver::AttributeFilter.add_attributes( object_attributes_hash.keys )

  child_objects = identify_object( rules ).collect{ | test_object_xml |

    # 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)
    test_object_adapter = sut.instance_variable_get( :@test_object_adapter )
            
    # 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
    unless identification_directives.has_key?( :__parent_application ) || rules.has_key?( :parent_application )
          
      # retrieve application test object xml element
      application_test_object_xml = test_object_adapter.retrieve_parent_application( test_object_xml )

      unless application_test_object_xml.nil?

        # retrieve test object id from xml
        object_id = test_object_adapter.test_object_element_attribute( application_test_object_xml, 'id', nil ).to_i

        # retrieve test object name from xml
        object_name = test_object_adapter.test_object_element_attribute( application_test_object_xml, 'name', nil ).to_s

        # retrieve test object type from xml
        object_type = test_object_adapter.test_object_element_attribute( application_test_object_xml, 'type', nil ).to_s 
          
        # calculate object cache hash key
        hash_key = test_object_adapter.test_object_hash( object_id, object_type, object_name )
          
        parent_cache = sut.instance_variable_get( :@child_object_cache )                       
        
        # get cached test object from parents child objects cache if found; if not found from cache pass newly created object as is
        if parent_cache.has_object?( hash_key )

          rules[ :parent_application ] = parent_cache[ hash_key ]
          
        else
          
          # create application test object            
          rules[ :parent_application ] = make_test_object( 
        
            :parent => sut,          
            :parent_application => nil,
            :xml_object => application_test_object_xml,

            # object identification attributes
            :object_attributes_hash => { :name => object_name, :type => object_type }

          )
          
        end

      else

        # could not retrieve parent application object
        rules[ :parent_application ] = nil
      
      end

      # store application test object to new test object 
      rules[ :parent_application ].instance_variable_set( :@parent_application, rules[ :parent_application ] )
      
    end
    
    # create new test object
    make_test_object( 
    
      # test objects parent test object
      :parent => rules[ :parent ],

      # test objects parent application 
      :parent_application => rules[ :parent_application ],

      # xml element to test object
      :xml_object => test_object_xml,

      # object identification attributes
      :object_attributes_hash => object_attributes_hash,

      :identification_directives => identification_directives

    )
             
  }

  # return test object(s); either one or multiple objects
  identification_directives[ :__multiple_objects ] ? child_objects : child_objects.first

end

.get_timeoutObject

Function gets the timeout used in TestObjectFactory

returns

Numeric

Timeout



650
651
652
653
654
655
656
# File 'lib/tdriver/base/test_object/factory.rb', line 650

def self.get_timeout

  warn "warning: deprecated method TDriver::TestObjectFactory#get_timeout; please use TDriver::TestObjectFactory#timeout instead"

  @timeout

end

.identify_object(rules) ⇒ Object

TODO: document me



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/tdriver/base/test_object/factory.rb', line 128

def self.identify_object( rules )
  
  # retrieve test object identification directives; e.g. :__index, :__xy_sorting etc 
  directives = rules[ :identification_directives ]
  
  # retrieve sut object
  sut = rules[ :parent ].instance_variable_get( :@sut )

  # retrieve sut objects test object adapter
  test_object_adapter = sut.instance_variable_get( :@test_object_adapter )

  # add object identification attribute keys to dynamic attributes white list
  TDriver::AttributeFilter.add_attributes( rules[ :object_attributes_hash ].keys )

  # search parameters for find_objects feature    
  search_parameters = make_object_search_params( rules[ :parent ], rules[ :object_attributes_hash ] )
  
  # default rules
  directives.default_values(
        
    # get timeout from rules hash or TestObjectFactory
    :__timeout => @timeout,

    # get retry interval from rules hash or TestObjectFactory
    :__retry_interval => @_retry_interval,
     
    # determine that are we going to retrieve multiple test objects or just one
    :__multiple_objects => false,

    # determine that should all child objects childrens be retrieved
    :__find_all_children => true,

    # determine that did user give index value
    :__index_given => directives.has_key?( :__index ),

    # use sorting if index given
    :__xy_sorting => directives.has_key?( :__index ),

    # determine index of test object to be retrieved
    :__index => 0,
    
    :__retriable_allowed_exceptions => [ MobyBase::TestObjectNotFoundError, MobyBase::MultipleTestObjectsIdentifiedError ]
             
  )

  # if sorting enabled; retrieve application layout direction first
  if directives[ :__xy_sorting ] == true

    parent_application = directives[ :__parent_application ] || rules[ :parent_application ]

    # application could be retrieved also like this...
    # rules[ :parent ].instance_variable_get( :@parent_application )

    # when e.g. wait_child is called to SUT, TDriver is unable to determine layout direction used for sorting/indexing
    if rules[ :parent ].sut?

      application_layout_direction = directives[ :__layout_direction ]
    
      raise RuntimeError, 'layout direction is not available for indexing/xy_sorting; please use e.g. :__layout_direction => "LeftToRight"' if application_layout_direction.blank?
            
    else
    
      # retrieve layout direction from application object if available
      unless parent_application.nil?

        begin

          application_layout_direction = ""

          if directives[ :__layout_direction ].blank?
          
            application_layout_direction = parent_application.attribute( 'layoutDirection' ).to_s 
          
          end

          raise if application_layout_direction.empty?

        rescue

          application_layout_direction = directives[ :__layout_direction ]

          # parent application not defined/available, use default value
          application_layout_direction = 'LeftToRight' if application_layout_direction.blank?

        end

      else

        raise RuntimeError, 'parent application not given; unable to retrieve layoutDirection attribute'

      end

    end


  end
  
  # identify objects until desired matches found or timeout exceeds
  MobyUtil::Retryable.until( 

    # maximum time used for retrying, if timeout exceeds pass last raised exception
    :timeout => directives[ :__timeout ], 

    # interval used before retrying
    :interval => directives[ :__retry_interval ],

    # following exceptions are allowed; Retry until timeout exceeds or other exception type is raised
    :exception => directives[ :__retriable_allowed_exceptions ]
    
  ){

    # refresh sut
    sut.refresh( directives[ :__refresh_arguments ], search_parameters )

    # 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)
    test_object_adapter = sut.instance_variable_get( :@test_object_adapter )

    # retrieve objects from xml
    matches, rule = test_object_adapter.get_objects(
    
     rules[ :parent ].xml_data, 
     rules[ :object_attributes_hash ], 
     directives[ :__find_all_children ] 

    )
              
    # Temporary prevent users misleading :Text with :text (as they are different)
    if ( rules[ :object_attributes_hash ].has_key?(:Text) )

      rules[ :object_attributes_hash ][:text] = rules[ :object_attributes_hash ][:Text]

    end
    
    # If retrying and regexp search is turned on then update the rules for text search converting it to a regex 
    if ( 
          matches.empty? and 
          $parameters[ sut.id ][:elided_search, 'false'] == 'true' and 
          rules[ :object_attributes_hash ].has_key?(:text) and
          rules[ :object_attributes_hash ][ :text ].kind_of? String
      )
        text_string = rules[ :object_attributes_hash ][ :text ]
        if ( $parameters[ sut.id ][:elided_search_with_ellipsis , 'false'] == 'true' )
          ellipsis_char = ".*\xE2\x80\xA6"  # unicode \u2026 the ... character \xE2\x80\xA6
        else
          ellipsis_char = ""
        end
        elided_regex = Regexp.new( text_string[0..3] + ellipsis_char )
        rules[ :object_attributes_hash ][ :text ] = elided_regex
    end

    # raise exception if no matching object(s) found
    raise MobyBase::TestObjectNotFoundError, "Cannot find object with rule:\n#{ rules[ :object_attributes_hash ].inspect }" if matches.empty?

    # raise exception if multiple matches found and only one expected 
    if ( !directives[ :__multiple_objects ] ) && ( matches.count > 1 && !directives[ :__index_given ] )

      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"

      # raise exception (with list of paths to all matching objects) if multiple objects flag is false and more than one match found
      raise MobyBase::MultipleTestObjectsIdentifiedError, message
        
    end

    # sort matches if enabled
    if directives[ :__xy_sorting ] == true

      # sort elements
      test_object_adapter.sort_elements( matches, application_layout_direction )

    end

    # return result; one or multiple xml elements
    if directives[ :__multiple_objects ] && !directives[ :__index_given ]
    
      # return multiple test objects
      matches.to_a

    else

      # return only one test object  
      [ matches[ directives[ :__index ] ] ]

    end

  }
    
end

.make_object_search_params(test_object, creation_attributes) ⇒ Object

create test object search parameters for find_objects service



626
627
628
629
630
631
632
633
634
# File 'lib/tdriver/base/test_object/factory.rb', line 626

def self.make_object_search_params( test_object, creation_attributes )

  result = get_parent_params( test_object ).push( get_object_params( creation_attributes ) )

  # TODO: review find_objects controller
  # workaround? return empty hash if no search params were 
  result == [{}] ? {} : result

end

.make_test_object(rules) ⇒ Object

TODO: document me



492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
# File 'lib/tdriver/base/test_object/factory.rb', line 492

def self.make_test_object( rules )

  # get parent object from hash
  parent = rules[ :parent ]

  # retrieve sut object
  sut = parent.instance_variable_get( :@sut )

  # retrieve sut objects test object adapter
  #test_object_adapter = sut.instance_variable_get( :@sut_controller ).test_object_adapter
  test_object_adapter = sut.instance_variable_get( :@test_object_adapter )

  # retrieve sut objects test object factory
  #test_object_factory = sut.instance_variable_get( :@sut_controller ).test_object_factory
  test_object_factory = sut.instance_variable_get( :@test_object_factory )
  
  # xml object element      
  xml_object = rules[ :xml_object ]

  # additional rules, e.g. :__no_caching
  identification_directives = rules[ :identification_directives ] || {}

  # retrieve attributes
  #@test_object_adapter.fetch_attributes( xml_object, [ 'id', 'name', 'type', 'env' ], false )

  if xml_object.kind_of?( MobyUtil::XML::Element )

    # retrieve test object id from xml
    object_id = test_object_adapter.test_object_element_attribute( xml_object, 'id', nil ).to_i

    # retrieve test object name from xml
    object_name = test_object_adapter.test_object_element_attribute( xml_object, 'name', nil ).to_s

    # retrieve test object type from xml
    object_type = test_object_adapter.test_object_element_attribute( xml_object, 'type', nil ).to_s 

    # retrieve test object type from xml
    env = test_object_adapter.test_object_element_attribute( xml_object, 'env' ){ $parameters[ sut.id ][ :env ] }.to_s
    
  else
  
    # defaults - refactor this
    object_type = ""
    
    object_name = ""
    
    object_id = 0

    env = $parameters[ sut.id ][ :env ].to_s

  end
  
  # calculate object cache hash key
  hash_key = test_object_adapter.test_object_hash( object_id, object_type, object_name )
  
  # get reference to parent objects child objects cache
  parent_cache = rules[ :parent ].instance_variable_get( :@child_object_cache )

  # get cached test object from parents child objects cache if found; if not found from cache pass newly created object as is
  if parent_cache.has_object?( hash_key )

    # get test object from cache
    test_object = parent_cache[ hash_key ]

    # store xml_object to test object
    test_object.xml_data = xml_object

    # update test objects creation attributes (either cached object or just newly created child object)
    test_object.instance_variable_get( :@creation_attributes ).merge!( rules[ :object_attributes_hash ] )

  else
    
    #trick
    #rules[ :parent_application ] = parent if parent.type == 'vkb'

    # create test object
    test_object = MobyBase::TestObject.new( 
    
      :test_object_factory => test_object_factory, #self,
      :test_object_adapter => test_object_adapter, #@test_object_adapter,
      :creation_attributes => rules[ :object_attributes_hash ],
      :xml_object => xml_object,
      :sut => sut, 

      # set given parent in rules hash as parent object for new child test object    
      :parent => parent,

      # set given application test object in rules hash as parent application for new child test object
      :parent_application => rules[ :parent_application ]

    )

    # temp. variable for object type
    obj_type = object_type.clone

    # apply all test object related behaviours unless object type is 'application'
    obj_type << ';*' unless obj_type == 'application'

    # apply behaviours to test object
    TDriver::BehaviourFactory.apply_behaviour(

      :object       => test_object,
      :object_type  => [ *obj_type.split(';')       ], 
      :input_type   => [ '*', sut.input.to_s        ],
      :env          => [ '*', *env.to_s.split(";")  ],
      :version      => [ '*', sut.ui_version.to_s   ]

    )

    # create child accessors
    #test_object_adapter.create_child_accessors!( xml_object, test_object )

    # add created test object to parents child objects cache, unless explicitly disabled
    parent_cache.add_object( test_object ) unless identification_directives[ :__no_caching ] == true

  end

  # NOTE: Do not remove object_type from object attributes hash_rule due to it is used in find_objects service!
  #rules[ :object_attributes_hash ].delete( :type )
  
  # do not make test object verifications if we are operating on the sut itself (allow run to pass)
  unless parent.kind_of?( MobyBase::SUT )

    # verify ui state if any verifycation blocks given
    TDriver::TestObjectVerification.verify_ui_dump( sut ) unless sut.verify_blocks.empty?

  end

  # return test object
  test_object

end

.resetObject

TODO: document me



94
95
96
97
98
99
100
101
102
# File 'lib/tdriver/base/test_object/factory.rb', line 94

def self.reset

  # get timeout from parameters, use default value if parameter not found
  @timeout = $parameters[ :application_synchronization_timeout, "20" ].to_f

  # get timeout retry interval from parameters, use default value if parameter not found
  @_retry_interval = $parameters[ :application_synchronization_retry_interval, "1" ].to_f

end

.set_timeout(value) ⇒ Object



636
637
638
639
640
641
642
643
644
# File 'lib/tdriver/base/test_object/factory.rb', line 636

def self.set_timeout( value )

  warn "warning: deprecated method TDriver::TestObjectFactory#set_timeout( value ); please use TDriver::TestObjectFactory#timeout=( value ) instead"

  value.check_type( Numeric, "Wrong argument type $1 for timeout value (expected $2)" )

  @timeout = value

end

.timeoutObject

function to get timeout for TestObjectFactory



105
106
107
108
109
# File 'lib/tdriver/base/test_object/factory.rb', line 105

def self.timeout

  @timeout
  
end

.timeout=(value) ⇒ Object

Function to set timeout for TestObjectFactory This should be used only in unit testing, otherwise should not be used sets timeout used in identifying TestObjects to new timeout

params

new_timeout

Fixnum which defines the new timeout

raises

ArgumentError

if parameter is not kind of Fixnum



119
120
121
122
123
124
125
# File 'lib/tdriver/base/test_object/factory.rb', line 119

def self.timeout=( value )

  value.check_type( Numeric, "Wrong argument type $1 for timeout value (expected $2)" )

  @timeout = value

end