testability-driver 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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