testability-driver 1.0.3 → 1.0.4

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 (116) hide show
  1. data/lib/tdriver-devtools/behaviour/xml/rdoc_behaviour_xml_generator.rb +2 -2
  2. data/lib/tdriver-devtools/tdriver-devtools.rb +1 -1
  3. data/lib/tdriver-devtools/tests/feature_tests/lib/custom_rdoc_generator.rb +3 -3
  4. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_composition.rb +6 -1
  5. data/lib/tdriver/base/behaviour/behaviours/object_behaviour_description.rb +5 -3
  6. data/lib/tdriver/base/behaviour/behaviours/object_composition.rb +1 -1
  7. data/lib/tdriver/base/behaviour/factory.rb +225 -225
  8. data/lib/tdriver/base/errors.rb +1 -1
  9. data/lib/tdriver/base/state_object.rb +227 -179
  10. data/lib/tdriver/base/sut/controller.rb +2 -2
  11. data/lib/tdriver/base/sut/factory.rb +190 -182
  12. data/lib/tdriver/base/sut/generic/behaviours/application.rb +69 -25
  13. data/lib/tdriver/base/sut/generic/behaviours/controller.rb +1 -1
  14. data/lib/tdriver/base/sut/generic/behaviours/find.rb +4 -4
  15. data/lib/tdriver/base/sut/generic/behaviours/flash_behaviour.rb +3 -3
  16. data/lib/tdriver/base/sut/generic/behaviours/sut.rb +350 -165
  17. data/lib/tdriver/base/sut/generic/behaviours/switchbox_behaviour.rb +9 -9
  18. data/lib/tdriver/base/sut/generic/behaviours/verification.rb +191 -103
  19. data/lib/tdriver/base/sut/generic/commands/application.rb +1 -1
  20. data/lib/tdriver/base/sut/generic/commands/key_sequence.rb +1 -1
  21. data/lib/tdriver/base/sut/generic/commands/screen_capture.rb +1 -1
  22. data/lib/tdriver/base/sut/generic/plugin.rb +1 -1
  23. data/lib/tdriver/base/sut/sut.rb +5 -1
  24. data/lib/tdriver/base/test_object/abstract.rb +136 -151
  25. data/lib/tdriver/base/test_object/adapter.rb +293 -82
  26. data/lib/tdriver/base/test_object/behaviours/syncronization.rb +20 -17
  27. data/lib/tdriver/base/test_object/behaviours/test_object.rb +159 -532
  28. data/lib/tdriver/base/test_object/cache.rb +1 -1
  29. data/lib/tdriver/base/test_object/factory.rb +254 -605
  30. data/lib/tdriver/base/test_object/identificator.rb +1 -1
  31. data/lib/tdriver/base/test_object/loader.rb +1 -1
  32. data/lib/tdriver/base/test_object/verification.rb +17 -17
  33. data/lib/tdriver/loader.rb +20 -9
  34. data/lib/tdriver/report/report.rb +5 -0
  35. data/lib/tdriver/report/report_creator.rb +2 -2
  36. data/lib/tdriver/report/report_cucumber_listener.rb +4 -4
  37. data/lib/tdriver/report/report_cucumber_reporter.rb +4 -4
  38. data/lib/tdriver/report/report_execution_statistics.rb +22 -22
  39. data/lib/tdriver/report/report_grouping.rb +2 -2
  40. data/lib/tdriver/report/report_javascript.rb +11 -4
  41. data/lib/tdriver/report/report_test_case_run.rb +2 -2
  42. data/lib/tdriver/report/report_test_run.rb +5 -5
  43. data/lib/tdriver/report/report_test_unit.rb +74 -26
  44. data/lib/tdriver/report/report_writer.rb +70 -13
  45. data/lib/tdriver/tdriver.rb +17 -8
  46. data/lib/tdriver/util/common/array.rb +1 -1
  47. data/lib/tdriver/util/common/crc16.rb +1 -1
  48. data/lib/tdriver/util/common/environment.rb +1 -1
  49. data/lib/tdriver/util/common/file.rb +18 -9
  50. data/lib/tdriver/util/common/gem.rb +1 -1
  51. data/lib/tdriver/util/common/hash.rb +21 -0
  52. data/lib/tdriver/util/common/kernel.rb +1 -1
  53. data/lib/tdriver/util/common/loader.rb +5 -2
  54. data/lib/tdriver/util/common/numeric.rb +54 -3
  55. data/lib/tdriver/util/common/retryable.rb +30 -12
  56. data/lib/tdriver/util/common/stackable.rb +185 -0
  57. data/lib/tdriver/util/common/string.rb +21 -5
  58. data/lib/tdriver/util/{dbaccess/dbaccess.rb → database/access.rb} +4 -1
  59. data/lib/tdriver/util/{dbaccess/dbconnection.rb → database/connection.rb} +3 -0
  60. data/lib/tdriver/util/{dbaccess → database}/error.rb +0 -1
  61. data/lib/tdriver/util/{dbaccess → database}/loader.rb +5 -6
  62. data/lib/tdriver/util/{dynamic_attribute_filter.rb → filters/dynamic_attributes.rb} +1 -1
  63. data/lib/tdriver/util/hooking/hooking.rb +477 -0
  64. data/lib/tdriver/util/loader.rb +35 -29
  65. data/lib/tdriver/util/localisation/error.rb +0 -1
  66. data/lib/tdriver/util/localisation/loader.rb +1 -4
  67. data/lib/tdriver/util/localisation/localisation.rb +30 -27
  68. data/lib/tdriver/util/{common.rb → logger/loader.rb} +2 -4
  69. data/lib/tdriver/util/logger/logger.rb +574 -0
  70. data/lib/tdriver/util/operator_data/loader.rb +4 -3
  71. data/lib/tdriver/util/operator_data/operator_data.rb +5 -5
  72. data/lib/tdriver/util/parameter/parameter.rb +7 -1
  73. data/lib/tdriver/util/parameter/parameter_hash.rb +1 -1
  74. data/lib/tdriver/util/parameter/parameter_template.rb +1 -1
  75. data/lib/tdriver/util/parameter/parameter_user_api.rb +28 -20
  76. data/lib/tdriver/util/parameter/parameter_xml.rb +1 -1
  77. data/lib/tdriver/util/plugin/abstract.rb +1 -1
  78. data/lib/tdriver/util/plugin/service.rb +1 -1
  79. data/lib/tdriver/util/{localisation.rb → recorder/loader.rb} +4 -3
  80. data/lib/tdriver/util/recorder/recorder.rb +66 -0
  81. data/lib/tdriver/util/recorder/scripter.rb +258 -0
  82. data/lib/tdriver/util/{stats.rb → statistics/statistics.rb} +7 -8
  83. data/lib/tdriver/util/user_data/error.rb +0 -1
  84. data/lib/tdriver/util/user_data/loader.rb +1 -2
  85. data/lib/tdriver/util/user_data/user_data.rb +6 -6
  86. data/lib/tdriver/util/video/camera.rb +67 -0
  87. data/lib/tdriver/util/video/camera_linux.rb +139 -0
  88. data/lib/tdriver/util/video/camera_windows.rb +174 -0
  89. data/lib/tdriver/util/video/loader.rb +31 -0
  90. data/lib/tdriver/util/video/video_utils.rb +139 -0
  91. data/lib/tdriver/util/xml/abstraction.rb +56 -5
  92. data/lib/tdriver/util/xml/builder.rb +2 -5
  93. data/lib/tdriver/util/{parameter.rb → xml/comment.rb} +10 -2
  94. data/lib/tdriver/util/xml/loader.rb +32 -22
  95. data/lib/tdriver/util/xml/nil_node.rb +2 -2
  96. data/lib/tdriver/util/xml/parsers/loader.rb +0 -1
  97. data/lib/tdriver/util/xml/parsers/nokogiri/abstraction.rb +18 -44
  98. data/lib/tdriver/util/xml/parsers/nokogiri/attribute.rb +9 -13
  99. data/lib/tdriver/util/xml/parsers/nokogiri/builder.rb +9 -3
  100. data/lib/tdriver/util/xml/parsers/nokogiri/comment.rb +39 -0
  101. data/lib/tdriver/util/xml/parsers/nokogiri/document.rb +6 -11
  102. data/lib/tdriver/util/xml/parsers/nokogiri/element.rb +2 -122
  103. data/lib/tdriver/util/xml/parsers/nokogiri/loader.rb +26 -16
  104. data/lib/tdriver/util/xml/parsers/nokogiri/node.rb +203 -0
  105. data/lib/tdriver/util/xml/parsers/nokogiri/nodeset.rb +1 -2
  106. data/lib/tdriver/util/xml/parsers/nokogiri/text.rb +2 -20
  107. data/lib/tdriver/util/xml/xml.rb +52 -20
  108. data/lib/tdriver/verify/verify.rb +238 -81
  109. data/xml/behaviours/generic.xml +12 -10
  110. metadata +156 -180
  111. data/lib/tdriver/base/test_object/factory_new.rb +0 -202
  112. data/lib/tdriver/util/hooking.rb +0 -434
  113. data/lib/tdriver/util/logger.rb +0 -506
  114. data/lib/tdriver/util/recorder.rb +0 -297
  115. data/lib/tdriver/util/video_utils.rb +0 -384
  116. data/lib/tdriver/util/xml/nil_element.rb +0 -89
@@ -21,6 +21,13 @@ module MobyUtil
21
21
 
22
22
  class Retryable
23
23
 
24
+ # TODO: document me
25
+ def self.sleep_retry_interval( time )
26
+
27
+ sleep( time )
28
+
29
+ end
30
+
24
31
  # Function to retry code block for x times if exception raises
25
32
  # == params
26
33
  # options:: Hash of options
@@ -30,22 +37,21 @@ module MobyUtil
30
37
  # == returns
31
38
  def self.while( options = {}, &block )
32
39
 
33
- options = { :tries => 1, :interval => 0, :exception => Exception }.merge( options )
40
+ # default options
41
+ options.default_values( :tries => 1, :interval => 0, :exception => Exception )
34
42
 
35
43
  attempt = 1
36
44
 
37
45
  begin
38
46
 
39
47
  # yield given block and pass attempt number as parameter
40
- return yield( attempt )
48
+ yield( attempt )
41
49
 
42
50
  rescue *options[ :exception ]
43
-
44
- #if ( options[ :tries ] -= 1) > 0 && ![ *options[ :unless ] ].include?( $!.class )
45
51
 
46
52
  if ( attempt < options[ :tries ] ) && ![ *options[ :unless ] ].include?( $!.class )
47
53
 
48
- sleep( options[ :interval ] ) if options[ :interval ] > 0
54
+ sleep_retry_interval( options[ :interval ] ) if options[ :interval ] > 0
49
55
 
50
56
  attempt += 1
51
57
 
@@ -57,8 +63,7 @@ module MobyUtil
57
63
  Kernel::raise $!
58
64
 
59
65
  end
60
-
61
- nil
66
+
62
67
  end
63
68
 
64
69
  # Function to retry code block until timeout expires if exception raises
@@ -70,28 +75,41 @@ module MobyUtil
70
75
  # == returns
71
76
  def self.until( options = {}, &block )
72
77
 
73
- options = { :timeout => 0, :interval => 0, :exception => Exception }.merge( options )
78
+ # default options
79
+ options.default_values( :timeout => 0, :interval => 0, :exception => Exception )
80
+
81
+ # store start time
74
82
  start_time = Time.now
75
83
 
84
+ # attempt number
85
+ attempt = 0
86
+
76
87
  begin
77
88
 
78
- return yield
89
+ # execute block
90
+ yield( attempt )
79
91
 
80
92
  rescue *options[ :exception ]
81
93
 
82
94
  if (Time.now - start_time) <= options[ :timeout ] && ![ *options[ :unless ] ].include?( $!.class )
83
- sleep( options[ :interval ] ) if options[ :interval ] > 0
95
+
96
+ sleep_retry_interval( options[ :interval ] ) if options[ :interval ] > 0
97
+
98
+ attempt += 1
99
+
84
100
  retry
101
+
85
102
  end
86
103
 
87
104
  # raise exception with correct exception backtrace
88
105
  Kernel::raise $!
89
106
 
90
- end
107
+ end
108
+
91
109
  end
92
110
 
93
111
  # enable hooking for performance measurement & debug logging
94
- MobyUtil::Hooking.instance.hook_methods( self ) if defined?( MobyUtil::Hooking )
112
+ TDriver::Hooking.hook_methods( self ) if defined?( TDriver::Hooking )
95
113
 
96
114
  end # Retryable
97
115
 
@@ -0,0 +1,185 @@
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 StackableValue
23
+
24
+ # TODO: document me
25
+ def initialize( value, explicit_format = [] )
26
+
27
+ @explicit_format = explicit_format.kind_of?( Array ) ? explicit_format : [ explicit_format ]
28
+
29
+ @stack = []
30
+
31
+ push( value )
32
+
33
+ end
34
+
35
+ # TODO: document me
36
+ def push( value )
37
+
38
+ unless @explicit_format.empty?
39
+
40
+ found = false
41
+
42
+ # collect verbose type list
43
+ verbose_type_list = @explicit_format.each_with_index.collect{ | type, index |
44
+
45
+ raise TypeError, "invalid argument type #{ type } for check_type. Did you mean #{ type.class }?" unless type.kind_of?( Class )
46
+
47
+ found = true if value.kind_of?( type )
48
+
49
+ # result string, separate types if multiple types given
50
+ "#{ ( ( index > 0 ) ? ( index + 1 < @explicit_format.count ? ", " : " or " ) : "" ) }#{ type.to_s }"
51
+
52
+ }.join
53
+
54
+ raise TypeError, "wrong variable format #{ value.class } for stackable value (expected #{ verbose_type_list })" unless found
55
+
56
+ end
57
+
58
+ # add to stack
59
+ @stack << value
60
+
61
+ end
62
+
63
+ # TODO: document me
64
+ def pop
65
+
66
+ @stack.pop unless ( @stack.count == 1 )
67
+
68
+ # return last value from stack
69
+ @stack.last
70
+
71
+ end
72
+
73
+ # TODO: document me
74
+ def restore
75
+
76
+ @stack = [ @stack.first ]
77
+
78
+ # return first value in stack array
79
+ @stack.last
80
+
81
+ end
82
+
83
+ # TODO: document me
84
+ def stacked?
85
+
86
+ # determine if there is values in stack
87
+ @stack.count > 1
88
+
89
+ end
90
+
91
+ # TODO: document me
92
+ def to_s
93
+
94
+ # return last value in stack array as string
95
+ @stack.last.to_s
96
+
97
+ end
98
+
99
+ # TODO: document me
100
+ def inspect
101
+
102
+ # return inspect of last value in stack array
103
+ @stack.last.inspect
104
+
105
+ end
106
+
107
+ # TODO: document me
108
+ def count
109
+
110
+ # return size of the stack array
111
+ @stack.count
112
+
113
+ end
114
+
115
+ # TODO: document me
116
+ def first
117
+
118
+ # return first value in stack array
119
+ @stack.first
120
+
121
+ end
122
+
123
+ # TODO: document me
124
+ def last
125
+
126
+ # return last value in stack array
127
+ @stack.last
128
+
129
+ end
130
+
131
+ # TODO: document me
132
+ def []( value )
133
+
134
+ # return last one if index is too high
135
+ value = -1 if ( value > @stack.count - 1 )
136
+
137
+ @stack[ value ]
138
+
139
+ end
140
+
141
+ # TODO: document me
142
+ def []=( position, value )
143
+
144
+ # return last one if index is too high
145
+ value = -1 if ( position > @stack.count - 1 )
146
+
147
+ @stack[ position ] = value
148
+
149
+ end
150
+
151
+ # TODO: document me
152
+ def set( value )
153
+
154
+ @stack[ -1 ] = value
155
+
156
+ end
157
+
158
+ def ==( value )
159
+
160
+ @stack.last == value
161
+
162
+ end
163
+
164
+ # TODO: document me
165
+ def kind_of?( klass )
166
+
167
+ # compary stacked value class
168
+ @stack.last.kind_of?( klass ) or klass == TDriver::StackableValue
169
+
170
+ end
171
+
172
+ # create required aliases
173
+ alias_method :size, :count
174
+
175
+ alias_method :<<, :push
176
+
177
+ alias_method :eql?, :==
178
+
179
+ alias_method :value=, :set
180
+
181
+ alias_method :value, :last
182
+
183
+ end # StackableValue
184
+
185
+ end # TDriver
@@ -52,16 +52,32 @@ class String
52
52
  # string:: String
53
53
  # == returns
54
54
  # TrueClass/FalseClass
55
- def to_boolean
55
+ def to_boolean( *default )
56
56
 
57
57
  if /^(true|false)$/i.match( self.to_s )
58
58
 
59
59
  $1.downcase == 'true'
60
60
 
61
61
  else
62
-
63
- #default
64
- Kernel::raise TypeError.new( "Unable to convert string \"#{ self }\" to boolean (Expected \”true\" or \"false\")" )
62
+
63
+ # pass default value if string didn't contain boolean
64
+ if default.count > 0
65
+
66
+ # retrieve first value from array
67
+ default = default.first
68
+
69
+ # check that argument type is correct
70
+ default.check_type( [ TrueClass, FalseClass ], 'wrong argument type $1 for to_boolean default value argument (expecting $2)')
71
+
72
+ # return default value as result
73
+ default
74
+
75
+ else
76
+
77
+ # raise exception if no default given
78
+ Kernel::raise TypeError, "Unable to convert string \"#{ self }\" to boolean (Expected \"true\" or \"false\")"
79
+
80
+ end
65
81
 
66
82
  end
67
83
 
@@ -123,7 +139,7 @@ module MobyUtil
123
139
  end
124
140
 
125
141
  # enable hooking for performance measurement & debug logging
126
- MobyUtil::Hooking.instance.hook_methods( self ) if defined?( MobyUtil::Hooking )
142
+ TDriver::Hooking.hook_methods( self ) if defined?( TDriver::Hooking )
127
143
 
128
144
  end # StringHelper
129
145
 
@@ -40,7 +40,7 @@ module MobyUtil
40
40
  # == description
41
41
  # Class Method that returns existing connections
42
42
  #
43
- def DBAccess.connections()
43
+ def self.connections()
44
44
  return @@_connections
45
45
  end
46
46
 
@@ -216,6 +216,9 @@ module MobyUtil
216
216
 
217
217
  end
218
218
 
219
+ # enable hoo./base/test_object/factory.rb:king for performance measurement & debug logging
220
+ TDriver::Hooking.hook_methods( self ) if defined?( TDriver::Hooking )
221
+
219
222
  end # DBAccess
220
223
 
221
224
  end # MobyUtil
@@ -34,6 +34,9 @@ module MobyUtil
34
34
  @password = password
35
35
  @dbh = nil
36
36
  end
37
+
38
+ # enable hoo./base/test_object/factory.rb:king for performance measurement & debug logging
39
+ TDriver::Hooking.hook_methods( self ) if defined?( TDriver::Hooking )
37
40
 
38
41
  end # class
39
42
 
@@ -17,7 +17,6 @@
17
17
  ##
18
18
  ############################################################################
19
19
 
20
-
21
20
  module MobyUtil
22
21
 
23
22
  # This error should be raised when no database type is defined
@@ -17,13 +17,12 @@
17
17
  ##
18
18
  ############################################################################
19
19
 
20
-
21
-
22
-
23
20
  # dbaccess related errors
24
21
  require File.expand_path( File.join( File.dirname( __FILE__ ), 'error.rb' ) )
25
22
 
26
- # dbaccess module implementation
27
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'dbaccess.rb' ) )
28
- require File.expand_path( File.join( File.dirname( __FILE__ ), 'dbconnection.rb' ) )
23
+ # database access module implementation
24
+ require File.expand_path( File.join( File.dirname( __FILE__ ), 'access.rb' ) )
25
+
26
+ # database connection module implementation
27
+ require File.expand_path( File.join( File.dirname( __FILE__ ), 'connection.rb' ) )
29
28
 
@@ -181,7 +181,7 @@ module MobyUtil
181
181
  end
182
182
 
183
183
  # enable hooking for performance measurement & debug logging
184
- MobyUtil::Hooking.instance.hook_methods( self ) if defined?( MobyUtil::Hooking )
184
+ TDriver::Hooking.hook_methods( self ) if defined?( TDriver::Hooking )
185
185
 
186
186
  end # DynamicAttributeFilter
187
187
 
@@ -0,0 +1,477 @@
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
+ module TDriver
20
+
21
+ class Hooking
22
+
23
+ # TODO: document me
24
+ class << self
25
+
26
+ @@non_wrappable_methods = [ 'instance' ]
27
+
28
+ # default values
29
+ @@wrapped_methods = {}
30
+ @@wrappee_count = 0
31
+
32
+ @@benchmark = {}
33
+
34
+ @@logger_instance = nil
35
+
36
+ $tdriver_hooking = TDriver::Hooking
37
+ $tdriver_hooking_elapsed_time_stack = []
38
+
39
+ private
40
+
41
+ # Function to hook a method
42
+ # == params
43
+ # base:: Class or Module
44
+ # method_name:: Name of the method
45
+ # method_type:: public, private or static
46
+ # == returns
47
+ def hook_method( base, method_name, method_type )
48
+
49
+ # create only one wrapper for each method
50
+ unless @@wrapped_methods.has_key?( "#{ base.name }::#{ method_name }" )
51
+
52
+ # evaluate the generated wrapper source code
53
+ eval("base.#{ base.class.name.downcase }_eval( \"#{ make_wrapper( base, method_name.to_s, method_type.to_s )}\" )") if [ Class, Module ].include?( base.class )
54
+
55
+ end
56
+
57
+ nil
58
+
59
+ end
60
+
61
+ # Function to hook static methods for given Class or Module
62
+ # == params
63
+ # base:: Target Class or Module
64
+ # == returns
65
+ def hook_static_methods( _base )
66
+
67
+ if [ Class, Module ].include?( _base.class )
68
+
69
+ _base.singleton_methods( false ).each { | method_name |
70
+
71
+ hook_method( _base, method_name.to_s, "static" ) unless @@non_wrappable_methods.include?( method_name.to_s ) # method_name.to_s for ruby 1.9 compatibility
72
+
73
+ }
74
+
75
+ end
76
+
77
+ nil
78
+
79
+ end
80
+
81
+ # Function to hook instance methods for given Class or Module
82
+ # == params
83
+ # base:: Target Class or Module
84
+ # == returns
85
+ def hook_instance_methods( _base )
86
+
87
+ if [ Class, Module ].include?( _base.class )
88
+
89
+ {
90
+ :public => _base.public_instance_methods( false ),
91
+ :private => _base.private_instance_methods( false ),
92
+ :protected => _base.protected_instance_methods( false )
93
+
94
+ }.each{ | method_type, methods |
95
+
96
+ # method_name.to_s for ruby 1.9 compatibility
97
+ methods.each { | method_name | hook_method( _base, method_name.to_s, method_type.to_s ) unless /__wrappee_\d+/i.match( method_name.to_s ) }
98
+
99
+ }
100
+
101
+ end
102
+
103
+ nil
104
+
105
+ end
106
+
107
+ # Function to retrieve method path (e.g. Module1::Module2::Class1)
108
+ # == params
109
+ # base:: Target Class or Module
110
+ # == returns
111
+ # String:: Method path
112
+ def method_path( _base )
113
+
114
+ [ Class, Module ].include?( _base.class ) ? _base.name : _base.class.name
115
+
116
+ end
117
+
118
+ # Function to generate unique name for wrappee method
119
+ # == params
120
+ # method_name:: Name of the target method
121
+ # == returns
122
+ # String:: Unique name for wrappee method
123
+ def create_wrappee_name( method_name )
124
+
125
+ wrappee_name = "non_pritanble_method_name" if ( wrappee_name = ( /[a-z0-9_]*/i.match( method_name ) ) ).length == 0
126
+
127
+ "__wrappee_#{ @@wrappee_count }__#{ wrappee_name }"
128
+
129
+ end
130
+
131
+ # Function for create source code of wrapper for method
132
+ # == params
133
+ # base:: Class or Module
134
+ # method_name:: Name of the method
135
+ # method_type:: public, private or static
136
+ # == returns
137
+ # String:: source code
138
+ def make_wrapper( base, method_name, method_type = nil )
139
+
140
+ # method name with namespace
141
+ base_and_method_name = "#{ base.name }::#{ method_name }"
142
+
143
+ # add method to benchmark table if enabled
144
+ if ENV[ 'TDRIVER_BENCHMARK' ].to_s.downcase == 'true'
145
+
146
+ @@benchmark[ base_and_method_name ] = {
147
+ :time_elapsed => 0,
148
+ :times_called => 0,
149
+ :time_elapsed_total => 0
150
+ }
151
+
152
+ end
153
+
154
+ # create new name for original method
155
+ original_method_name = create_wrappee_name( method_name )
156
+
157
+ # add method to wrapper methods list
158
+ @@wrapped_methods[ base_and_method_name ] = nil
159
+
160
+ @@wrappee_count += 1
161
+
162
+ case method_type
163
+
164
+ when 'public', 'private', 'static'
165
+
166
+ "#{
167
+ # this is needed if method is static
168
+ "class << self" if method_type == 'static'
169
+
170
+ }
171
+
172
+ # create a copy of original method
173
+ alias_method :#{ original_method_name }, :#{ method_name }
174
+
175
+ #{
176
+
177
+ if method_type == 'static'
178
+
179
+ # undefine original version if static method
180
+ "self.__send__( :undef_method, :#{ method_name } )"
181
+
182
+ else
183
+
184
+ # method visiblity unless method type is static
185
+ "#{ method_type }"
186
+
187
+ end
188
+
189
+ }
190
+
191
+ def #{ method_name }( *args, &block )
192
+
193
+ # log method call
194
+ $tdriver_hooking.log( '#{ method_path( base ) }.#{ method_name }', nil )
195
+
196
+ #{
197
+
198
+ if ENV[ 'TDRIVER_BENCHMARK' ].to_s.downcase == 'true'
199
+
200
+ "# store start time for performance measurement
201
+ start_time = Time.now
202
+
203
+ # Time elapsed in sub calls
204
+ $tdriver_hooking_elapsed_time_stack << 0.0
205
+
206
+ begin
207
+
208
+ # call and return result of original method
209
+ __send__(:#{ original_method_name }, *args, &block )
210
+
211
+ rescue
212
+
213
+ raise $!
214
+
215
+ ensure
216
+
217
+ # calculate actual elapsed time, including time elapsed in sub calls
218
+ elapsed_time = Time.now - start_time
219
+
220
+ # elapsed time in sub calls
221
+ elapsed_time_in_subcalls = $tdriver_hooking_elapsed_time_stack.pop || 0
222
+
223
+ # add elapsed time to caller method
224
+ $tdriver_hooking_elapsed_time_stack[ -1 ] += elapsed_time unless $tdriver_hooking_elapsed_time_stack.empty?
225
+
226
+ # store performance results to benchmark hash
227
+ $tdriver_hooking.update_method_benchmark( '#{ base_and_method_name }', elapsed_time_in_subcalls, elapsed_time )
228
+
229
+ end"
230
+
231
+ else
232
+
233
+ "# call original method
234
+ __send__(:#{ original_method_name }, *args, &block )"
235
+
236
+ end
237
+
238
+ }
239
+
240
+ end
241
+
242
+ private :#{ original_method_name }
243
+
244
+ #{
245
+
246
+ # this is needed if method is static
247
+ "end" if method_type == 'static'
248
+
249
+ }"
250
+
251
+ end # case
252
+
253
+ end # make_wrapper
254
+
255
+ end # self
256
+
257
+ # TODO: document me
258
+ def self.wrappee_count
259
+
260
+ @@wrappee_count
261
+
262
+ end
263
+
264
+ # TODO: document me
265
+ def self.wrappee_count=( value )
266
+
267
+ @@wrappee_count = value
268
+
269
+ end
270
+
271
+ # TODO: document me
272
+ def self.wrappee_methods
273
+
274
+ @@wrappee_methods
275
+
276
+ end
277
+
278
+ # TODO: document me
279
+ def self.wrappee_methods=( value )
280
+
281
+ @@wrappee_methods = value
282
+
283
+ end
284
+
285
+
286
+ # TODO: document me
287
+ def self.benchmark
288
+
289
+ @@benchmark
290
+
291
+ end
292
+
293
+ # TODO: document me
294
+ def self.benchmark=( value )
295
+
296
+ @@benchmark = value
297
+
298
+ end
299
+
300
+ # TODO: document me
301
+ def self.logger_instance
302
+
303
+ @@logger_instance
304
+
305
+ end
306
+
307
+ # Function to set logger instance used by wrapper
308
+ # == params
309
+ # logger_instance:: Instance of TDriver logger
310
+ # == returns
311
+ def self.logger_instance=( logger_instance )
312
+
313
+ @@logger_instance = logger_instance
314
+
315
+ end
316
+
317
+ # Function to create logger event - this method is called from wrapper
318
+ # == params
319
+ # text:: Text sent from wrapper
320
+ # arguments:: Not in use
321
+ # == returns
322
+ def self.log( text, *arguments )
323
+
324
+ @@logger_instance.debug( text.to_s ) if @@logger_instance
325
+
326
+ nil
327
+
328
+ end
329
+
330
+ # Function to hook all instance and static methods of target Class/Module
331
+ # == params
332
+ # base:: Target Class or Module
333
+ # == returns
334
+ def self.hook_methods( _base )
335
+
336
+ hook_static_methods( _base )
337
+
338
+ hook_instance_methods( _base )
339
+
340
+ nil
341
+
342
+ end
343
+
344
+ # Function to update method runtime & calls count for benchmark
345
+ # == params
346
+ # method_name:: Name of the target method
347
+ # time_elapsed_in_subcalls::
348
+ # total_time_elapsed::
349
+ def self.update_method_benchmark( method_name, time_elapsed_in_subcalls, total_time_elapsed )
350
+
351
+ @@benchmark[ method_name ].tap{ | hash |
352
+
353
+ hash[ :time_elapsed ] += total_time_elapsed - time_elapsed_in_subcalls
354
+ hash[ :time_elapsed_total ] += total_time_elapsed
355
+ hash[ :times_called ] += 1
356
+
357
+ }
358
+
359
+ end
360
+
361
+ def self.print_benchmark( rules = {} )
362
+
363
+ total_run_time = 0
364
+
365
+ # :sort => :total_time || :times_called || :average_time
366
+
367
+ rules = { :sort => :total_time, :order => :ascending, :show_uncalled_methods => true }.merge( rules )
368
+
369
+ puts "%-80s %8s %15s %15s %9s %15s" % [ 'Name:', 'Calls:', 'Time total:', 'W/O subcalls:', '%/run', 'Total/call:' ]
370
+ puts "%-80s %8s %15s %15s %9s %15s" % [ '-' * 80, '-' * 8, '-' * 15, '-' * 15, '-' * 8, '-' * 15 ]
371
+
372
+ table = @@benchmark
373
+
374
+ # calculate average time for method
375
+ table.each{ | key, value |
376
+
377
+ table[ key ][ :average_time ] = ( value[ :times_elapsed_total ] == 0 || value[ :times_called ] == 0 ) ? 0 : value[ :time_elapsed_total ] / value[ :times_called ]
378
+
379
+ total_run_time += value[ :time_elapsed ]
380
+
381
+ }
382
+
383
+ table = table.sort{ | method_a, method_b |
384
+
385
+ case rules[ :sort ]
386
+
387
+ when :name
388
+ method_a[ 0 ] <=> method_b[ 0 ]
389
+
390
+ when :times_called
391
+ method_a[ 1 ][ :times_called ] <=> method_b[ 1 ][ :times_called ]
392
+
393
+ when :total_time
394
+ method_a[ 1 ][ :time_elapsed_total ] <=> method_b[ 1 ][ :time_elapsed_total ]
395
+
396
+ when :total_time_no_subs
397
+ method_a[ 1 ][ :time_elapsed ] <=> method_b[ 1 ][ :time_elapsed ]
398
+
399
+ when :percentage
400
+
401
+ ( ( method_a[ 1 ][ :time_elapsed ].to_f / total_run_time.to_f ) * 100 ) <=> ( ( method_b[ 1 ][ :time_elapsed ].to_f / total_run_time.to_f ) * 100 )
402
+
403
+ when :average_time
404
+ method_a[ 1 ][ :average_time ] <=> method_b[ 1 ][ :average_time ]
405
+
406
+ else
407
+
408
+ Kernel::raise ArgumentError.new("Invalid sorting rule, valid rules are :name, :times_called, :total_time, :total_time_no_subs, :percentage or :average_time")
409
+
410
+ end
411
+
412
+ }
413
+
414
+ case rules[ :order ]
415
+
416
+ # do nothing
417
+ when :ascending
418
+
419
+ when :descending
420
+ table = table.reverse
421
+
422
+ else
423
+
424
+ Kernel::raise ArgumentError.new("Invalid sort order rule, valid rules are :ascending, :descending")
425
+
426
+ end
427
+
428
+ total_percentage = 0.0
429
+ total_time_elapsed_total = 0.0
430
+ total_average = 0.0
431
+ total_calls = 0
432
+
433
+ table.each{ | method |
434
+
435
+ puts "%-80s %8s %15.8f %15.8f %8.3f%% %15.8f" % [
436
+ method[ 0 ],
437
+ method[ 1 ][ :times_called ],
438
+ method[ 1 ][ :time_elapsed_total ],
439
+ method[ 1 ][ :time_elapsed ],
440
+
441
+ ( ( method[ 1 ][ :time_elapsed ].to_f / total_run_time.to_f ) * 100 ),
442
+
443
+ method[ 1 ][ :average_time ]
444
+ ] unless !rules[ :show_uncalled_methods ] && method[ 1 ][ :times_called ] == 0
445
+
446
+ total_percentage += ( ( method[ 1 ][ :time_elapsed ].to_f / total_run_time.to_f ) * 100 )
447
+
448
+ total_calls += method[ 1 ][ :times_called ]
449
+ total_time_elapsed_total += method[ 1 ][ :time_elapsed_total ]
450
+ total_average += method[ 1 ][ :average_time ]
451
+
452
+ }
453
+
454
+ puts "%-80s %8s %15s %15s %9s %15s" % [ '-' * 80, '-' * 8, '-' * 15, '-' * 15, '-' * 8, '-' * 15 ]
455
+
456
+ puts "%-80s %8s %15.6f %15.6f %8.3f%% %15.8f" % [ 'Total:', total_calls, total_time_elapsed_total, total_run_time, total_percentage, total_average ]
457
+
458
+ end
459
+
460
+ end # Hooking
461
+
462
+ end # TDriver
463
+
464
+ # deprecated
465
+ module MobyUtil
466
+
467
+ class Hooking
468
+
469
+ def self.instance
470
+
471
+ TDriver::Hooking
472
+
473
+ end
474
+
475
+ end # Hooking
476
+
477
+ end # MobyUtil