test_internals 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
- gem 'app_mode', '~> 0.0.1'
3
+ gem 'app_mode', '~> 1.0.0'
4
4
 
5
5
  group :rake do
6
6
  gem 'rake_tasks', '~> 0.0.1'
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- app_mode (0.0.2)
4
+ app_mode (1.0.1)
5
5
  rake (0.8.7)
6
- rake_tasks (0.0.1)
6
+ rake_tasks (0.0.4)
7
7
  rake (~> 0.8.7)
8
8
 
9
9
  PLATFORMS
10
10
  ruby
11
11
 
12
12
  DEPENDENCIES
13
- app_mode (~> 0.0.1)
13
+ app_mode (~> 1.0.0)
14
14
  rake_tasks (~> 0.0.1)
data/README CHANGED
@@ -1,15 +1,9 @@
1
1
  == Welcome to TestInternals
2
2
 
3
- TestInternals patches Test::Unit::TestCase to allow testing of private methods,
4
- as well as variables.
5
-
6
- The stack trace is also available, including the ability to check
7
- that specific parameter values were sent to a method.
8
-
9
- It will also prevent the application from stopping tests if exit is called.
10
- assert_alive and assert_dead have been included to assist in testing.
11
-
12
- There are also a number of assertions that have been added.
3
+ TestInternals patches Test::Unit::TestCase to allow
4
+ testing of private methods, as well as variables. The stack trace
5
+ is also available, including the ability to check that specific
6
+ parameters were sent to a method. This results in cotton candy goodness for all.
13
7
 
14
8
  == Getting Started
15
9
 
@@ -17,14 +11,68 @@ There are also a number of assertions that have been added.
17
11
 
18
12
  gem install test_internals
19
13
 
20
- 2. Require the gem in your gemfile:
14
+ 2. Require the gem in your Gemfile:
21
15
 
22
- gem 'test_internals', '~> 0.0.1'
16
+ gem 'test_internals', '~> 1.0.0'
23
17
 
24
- 3. Require the gem wherever you need shell commands:
18
+ 3. Require the gem wherever you need to use it:
25
19
 
26
20
  require 'test_internals'
27
21
 
22
+ == Overriding Default Behavior
23
+
24
+ To call methods that enable functionality or to override
25
+ variable settings, add an initialize method to your test
26
+ and call the desired method, calling super after:
27
+
28
+ def initialize
29
+ expose_all_variables
30
+ expose_stack
31
+ expose_class_methods
32
+ expose_instance_methods
33
+ @class = MyClass
34
+ init_object(param1, param2, ...)
35
+ # ...
36
+ super
37
+ end
38
+
39
+ NOTE: If it is not included in this example,
40
+ it is not expected to be used in the initialize method.
41
+
42
+ == Instance Variables
43
+
44
+ === @class
45
+
46
+ The @class variable, will exist for every test.
47
+ The class is inferred from the name of the test.
48
+ For example, a class named MyClass
49
+ is expected to be tested by a class named MyClassTest.
50
+
51
+ The default behavior may be overridden by specifying the class
52
+ in the initialize method of your test as shown above.
53
+
54
+ === @obj
55
+
56
+ This is only non-nil if init_object has been called in the initialize method
57
+ (and the class responds to the :new method).
58
+ See rdoc for additional details.
59
+
60
+ == Additional Notes
61
+
62
+ * Methods marked protected are intended to be used by sub-classes.
63
+
64
+ * Methods marked private are intended to be used only by the class itself
65
+ and are NOT intended for use in sub-classes.
66
+ If they are, results may be unpredictable.
67
+
68
+ * When send_to_class or send_to_object are called, the calls are wrapped such
69
+ that output is captured and not sent to the console.
70
+ The output may be retrieved via the following methods:
71
+
72
+ out #=> output to stdout
73
+ err #=> output to stderr
74
+ real_finis #=> An array [out, err]
75
+
28
76
  == Additional Documentation
29
77
 
30
78
  rake rdoc:app
@@ -34,16 +34,18 @@
34
34
 
35
35
  # Monkey patch Test::Unit::TestCase to make it do cool stuff.
36
36
  Test::Unit::TestCase.class_eval do
37
+ include TestInternals
38
+
37
39
  # Since this is in a class_eval, instance methods need to be wrapped up
38
40
  # in class_variable_set or ruby will throw warnings.
39
41
 
40
42
  # Indicates whether the class has already been initialized.
41
43
  # This combined with @@class_name prevents duplicate patching.
42
- class_variable_set(:@@initialized, false)
44
+ class_variable_set(:@@initialized, nil)
43
45
 
44
46
  # Keeps track of the class that has most recently been initialized.
45
47
  # This combined with @@initialized prevents duplicate patching.
46
- class_variable_set(:@@class_name, '')
48
+ class_variable_set(:@@class_name, nil)
47
49
 
48
50
  # Initializes the class
49
51
  # and exposes private methods and variables of the class that is being tested.
@@ -51,19 +53,26 @@ Test::Unit::TestCase.class_eval do
51
53
  # Call initialize on the superclass.
52
54
  super
53
55
 
54
- @obj = nil
56
+ @obj = nil
57
+ @class = nil unless defined?(@class)
58
+
59
+ @init_object = nil unless defined?(@init_object)
60
+ @init_object_params = nil unless defined?(@init_object_params)
61
+
62
+ @expose_instance_methods = nil unless defined?(@expose_instance_methods)
63
+ @expose_class_methods = nil unless defined?(@expose_class_methods)
64
+ @expose_variables = nil unless defined?(@expose_variables)
65
+ @expose_stack = nil unless defined?(@expose_stack)
55
66
 
56
67
  reset_io
57
- reset_trace
58
68
 
59
69
  # This block ensures that tests still work if there is not a class that
60
70
  # corresponds with the test file/class.
61
- @class = nil
62
71
  begin
63
72
  # Get the class that is being tested.
64
73
  # Assume that the name of the class is found by removing 'Test'
65
74
  # from the test class.
66
- @class = Kernel.const_get(self.class.name.gsub(/Test$/, ''))
75
+ @class ||= Kernel.const_get(self.class.name.gsub(/Test$/, ''))
67
76
  @@initialized = ((@class.name == @@class_name) && @@initialized)
68
77
  @@class_name = @class.name
69
78
  rescue
@@ -72,34 +81,41 @@ Test::Unit::TestCase.class_eval do
72
81
  end
73
82
 
74
83
  # Only patch if this code has not yet been run.
75
- if !@@initialized and @class.class.name != 'Module'
76
- set_instance_method_wrappers
84
+ if !@@initialized
85
+ set_instance_method_wrappers if @expose_stack
77
86
 
78
87
  # Expose private class methods.
79
88
  # We will only expose the methods we are responsible for creating.
80
89
  # (i.e. subtracting the superclass's private methods)
81
90
  expose_private_methods(:class,
82
91
  @class.private_methods -
83
- @class.superclass.private_methods)
92
+ @class.superclass.private_methods) if @expose_class_methods
84
93
 
85
94
  # Expose private instance methods.
86
95
  # We will only expose the methods we are responsible for creating.
87
96
  # (i.e. subtracting the superclass's private methods)
88
97
  expose_private_methods(:instance,
89
98
  @class.private_instance_methods -
90
- @class.superclass.private_instance_methods)
99
+ @class.superclass.private_instance_methods) if @expose_instance_methods
91
100
 
92
101
  # Expose variables.
93
102
  # Requires that variables are assigned to in the constructor.
94
- wrap_output {
95
- expose_variables(@class.class_variables +
96
- @class.new([]).instance_variables)
97
- }
103
+ if @expose_variables
104
+ init_with_defaults if new_object_on_init?
105
+ instance_variable_list = @obj.nil? ? [] : @obj.instance_variables
106
+ expose_variables @class.class_variables + instance_variable_list
107
+ end
98
108
 
99
109
  # Indicate that this code has been run.
100
110
  @@initialized = true
101
111
  end
102
112
 
113
+ # This is potentially called a second time so that the object will
114
+ # include any goodies we have added here.
115
+ init_with_defaults if new_object_on_init?
116
+
117
+ reset_trace
118
+
103
119
  # If initializing the class with @class.new above kills the app,
104
120
  # we need to set it back to running, but we want to do this regardless.
105
121
  reset_app_state
@@ -110,194 +126,149 @@ Test::Unit::TestCase.class_eval do
110
126
  # Tracing is set up here so that it is only running during tests.
111
127
  #
112
128
  # If you want to disable tracing, simply override the setup method
113
- # without calling super. (It would be good form to also override teardown).
129
+ # without calling super.
114
130
  def setup
115
- set_trace_func proc { |event, file, line, id, binding, class_name|
116
- if class_name == @class and
117
- @stack_trace.last != {:class => class_name.name, :method => id}
118
- @stack_trace << {
119
- :class => class_name.name,
120
- :method => id,
121
- }
122
- end
123
- }
131
+ if @expose_stack
132
+ set_trace_func proc { |event, file, line, id, binding, class_name|
133
+ if class_name == @class and
134
+ @stack_trace.last != {:class => class_name.name, :method => id}
135
+ @stack_trace << {
136
+ :class => class_name.name,
137
+ :method => id,
138
+ }
139
+ end
140
+ }
141
+ end
124
142
  end
125
143
 
126
144
  # Clean up after each test.
127
- #
128
- # If you disable tracing, it would be good form to override this method
129
- # as well without calling super.
130
145
  def teardown
131
- set_trace_func nil
146
+ set_trace_func nil if @expose_stack
132
147
  end
133
148
 
134
149
  ############################################################################
135
- private
150
+ protected
136
151
  ############################################################################
137
152
 
153
+ # Protected methods are intended for use in this class and/or sub-classes.
154
+
138
155
  ############################################################################
139
- # Monkey patching methods for the class being tested.
156
+ # @obj and @class-related methods
140
157
  ############################################################################
141
158
 
142
- # Monkey patch the class's initializer to enable tracing
143
- # with parameters and results.
144
- def set_initializer
145
- @class.class_eval do
146
- attr_accessor :trace
147
-
148
- alias :test_case_initialize :initialize
149
- def initialize(*args)
150
- @trace = []
151
- result = test_case_initialize(*args)
152
- return result
153
- end
154
- end
159
+ # Creates a new instance of the class using the arguments that are passed in.
160
+ #
161
+ # This method also resets the states of other variables prior to creation.
162
+ # ==== Input
163
+ # [*args : Array] The parameters that will be used to create a new instance.
164
+ def create(*args)
165
+ reset_io
166
+ reset_trace
167
+ reset_app_state
168
+ @obj = init_new_object(*args)
155
169
  end
156
170
 
157
- # Loop through the instance methods, calling set_instance_methods for each.
158
- def set_instance_method_wrappers
159
- [
160
- :public_instance_methods,
161
- :protected_instance_methods,
162
- :private_instance_methods
163
- ].each do |method_id|
164
-
165
- scope = method_id.to_s.gsub(/_.*/, '')
171
+ # Creates a new object using the specified parameters.
172
+ # ==== Input
173
+ # [*args : Array] The parameters to send to the new method
174
+ # when creating the object.
175
+ def init_new_object(*args)
176
+ @obj = send_to_class(:new, *args)
177
+ end
166
178
 
167
- set_instance_methods(@class.send(method_id) -
168
- @class.superclass.send(method_id), scope)
179
+ # Sets the value of the variable that indicates whether a new object
180
+ # should be created and sets the parameters that will be used.
181
+ # ==== Output
182
+ # [params : Array] The parameters to use when creating the object.
183
+ # ==== Notes
184
+ # This method should only be called from a child class's initialize method.
185
+ # Calling it elsewhere could cause unexpected results.
186
+ def init_object(*params)
187
+ @init_object = true
188
+
189
+ case params.length
190
+ when 0
191
+ @init_object_params = nil
192
+ when 1
193
+ @init_object_params = params[0]
194
+ else
195
+ @init_object_params = *params
169
196
  end
170
-
171
- # If this is not at the end, the loop will attempt to do it's thing
172
- # with the constructor created in this method, which is not necessary.
173
- set_initializer
174
197
  end
175
198
 
176
- # Loop through the list of methods that are passed in,
177
- # creating a wrapper method that enables tracing.
178
- #
179
- # Tracing data includes method name, parameters, and result.
180
- # ==== Input
181
- # [method_list : Array] A list of methods that will have wrapping functions
182
- # created to enable tracing.
183
- # [scope : String] The scope of the original function.
184
- def set_instance_methods(method_list, scope)
185
- method_list.each do |method_id|
186
- # Setters and methods that accept blocks do not appear to work.
187
- next if method_id =~ /=/ or method_id =~ /wrap_output/
188
-
189
- # Build the method.
190
- new_method = <<-DOC
191
- alias :test_case_#{method_id} :#{method_id}
192
- def #{method_id}(*args)
193
- result = test_case_#{method_id}(*args)
194
- @trace << {
195
- :method => '#{method_id}',
196
- :args => args,
197
- :result => result
198
- }
199
- return result
200
- end
201
- #{scope} :#{method_id}
202
- DOC
203
-
204
- # Add the method to the class.
205
- @class.class_eval do
206
- eval(new_method)
207
- end
208
- end
199
+ # Initializes a new object using the default parameters.
200
+ def init_with_defaults
201
+ init_new_object(*@init_object_params)
209
202
  end
210
203
 
211
- # Expose the private methods that are passed in. New methods will be created
212
- # with the old method name followed by '_public_test'. If the original
213
- # method contained a '?', it will be removed in the new method.
204
+ # Sends a call to the class.
214
205
  # ==== Input
215
- # [type : Symbol] Indicates whether to handle instance or class methods.
216
- #
217
- # Only :class and :instance are supported.
218
- # [methods : Array] An array of the methods to expose.
219
- def expose_private_methods(type, methods)
220
- # Get the text that the method should be wrapped in.
221
- method_wrapper = wrapper(type)
222
-
223
- # Loop through the methods.
224
- methods.each do |method|
225
- # Remove ?s.
226
- new_method = method.to_s.gsub(/\?/, '')
227
-
228
- # This is the new method.
229
- new_method = <<-DOC
230
- def #{new_method}_public_test(*args)
231
- #{method}(*args)
232
- end
233
- DOC
234
-
235
- # Add the wrapping text.
236
- new_method = method_wrapper % [new_method]
237
-
238
- # Add the method to the class.
239
- @class.class_eval do
240
- eval(new_method)
241
- end
242
- end
206
+ # [method : Symbol, String] The method to call.
207
+ # [*args : Array] The parameters to send.
208
+ def send_to_class(method, *args)
209
+ return send_to(@class, method.to_sym, *args)
243
210
  end
244
211
 
245
- # Expose the variables.
246
- #
247
- # New methods will be created (a getter and a setter) for each variable.
248
- #
249
- # Regardless of the type of variable, these methods are only available
250
- # via an instance.
212
+ # Sends a method to the object in the class variable.
251
213
  # ==== Input
252
- # [variables : Array] An array of variables to expose.
253
- def expose_variables(variables)
254
- # Get the text that the methods should be wrapped in.
255
- var_wrapper = wrapper(:instance)
256
-
257
- # Loop through the variables
258
- variables.each do |var|
259
- # Remove any @s.
260
- new_method = var.to_s.gsub(/@/, '')
214
+ # [method : Symbol, String] The name of the method to call.
215
+ # [*args : Array] Parameters to use when calling the method.
216
+ def send_to_object(method, *args)
217
+ create(*args)
218
+ assert_alive
219
+ return send_to(@obj, method.to_sym, *args)
220
+ end
261
221
 
262
- # These are the new getter and setters.
263
- new_method = <<-DOC
264
- def #{new_method}_variable_method
265
- #{var}
266
- end
222
+ ############################################################################
223
+ # Enable Functionality - These should only be called in initialize of a child.
224
+ ############################################################################
267
225
 
268
- def #{new_method}_variable_method=(value)
269
- #{var} = value
270
- end
271
- DOC
226
+ # Indicate that class and instance variables should be made available
227
+ # via public methods.
228
+ def expose_all_variables
229
+ @expose_variables = true
230
+ end
272
231
 
273
- # Add the wrapping text.
274
- new_method = var_wrapper % [new_method]
232
+ # Indicate that private class methods should be made available
233
+ # via public class methods.
234
+ def expose_class_methods
235
+ @expose_class_methods = true
236
+ end
275
237
 
276
- # Add the methods to the class.
277
- @class.class_eval do
278
- eval(new_method)
279
- end
280
- end
238
+ # Indicate that private instance methods should be made available
239
+ # via public instance methods.
240
+ def expose_instance_methods
241
+ @expose_instance_methods = true
281
242
  end
282
243
 
283
- # Returns the wrapping text for the specified type of method.
284
- # ==== Input
285
- # [type : Symbol] Indicates whether to handle instance or class methods.
286
- #
287
- # Only :class & :instance are supported.
288
- # ==== Output
289
- # [String] The text that the specified type of method should be wrapped in.
290
- def wrapper(type)
291
- case type
292
- when :class then 'class << self;%s;end'
293
- when :instance then '%s'
294
- end
244
+ # Enables stack tracing so that assertions which rely on knowing
245
+ # which methods were called may be used.
246
+ def expose_stack
247
+ @expose_stack = true
295
248
  end
296
249
 
297
250
  ############################################################################
298
251
  # I/O support methods.
299
252
  ############################################################################
300
253
 
254
+ # Returns the output from stdout as a string.
255
+ # ==== Output
256
+ # [String] The output from stdout.
257
+ #
258
+ # All trailing line feeds are removed.
259
+ def out
260
+ @out.respond_to?(:string) ? @out.string.gsub(/\n*\z/, '') : ''
261
+ end
262
+
263
+ # Returns the output from stderr as a string.
264
+ # ==== Output
265
+ # [String] The output from stderr.
266
+ #
267
+ # All trailing line feeds are removed.
268
+ def err
269
+ @err.respond_to?(:string) ? @err.string.gsub(/\n*\z/, '') : ''
270
+ end
271
+
301
272
  # Return the actual output to stdout and stderr.
302
273
  # ==== Output
303
274
  # [Array] Two element array of strings.
@@ -309,6 +280,12 @@ Test::Unit::TestCase.class_eval do
309
280
  return out, err
310
281
  end
311
282
 
283
+ # Reset the stdout and stderr stream variables.
284
+ def reset_io
285
+ @out = StringIO.new
286
+ @err = StringIO.new
287
+ end
288
+
312
289
  # Wrap a block to capture the output to stdout and stderr.
313
290
  # ==== Input
314
291
  # [&block : Block] The block of code that will have stdout and stderr trapped.
@@ -317,55 +294,21 @@ Test::Unit::TestCase.class_eval do
317
294
  $stdout = @out
318
295
  $stderr = @err
319
296
  yield
297
+ rescue SystemExit
298
+ AppState.state = :dead
320
299
  ensure
321
300
  $stdout = STDOUT
322
301
  $stderr = STDERR
323
302
  end
324
303
  end
325
304
 
326
- # Returns the output from stdout as a string.
327
- # ==== Output
328
- # [String] The output from stdout.
329
- #
330
- # All trailing line feeds are removed.
331
- def out
332
- @out.respond_to?(:string) ? @out.string.gsub(/\n*\z/, '') : ''
333
- end
334
-
335
- # Returns the output from stderr as a string.
336
- # ==== Output
337
- # [String] The output from stderr.
338
- #
339
- # All trailing line feeds are removed.
340
- def err
341
- @err.respond_to?(:string) ? @err.string.gsub(/\n*\z/, '') : ''
342
- end
343
-
344
- # Reset the stdout and stderr stream variables.
345
- def reset_io
346
- @out = StringIO.new
347
- @err = StringIO.new
348
- end
349
-
350
305
  ############################################################################
351
306
  # Support methods.
352
307
  ############################################################################
353
308
 
354
- # Indicates whether the specified method has been called on a given class.
355
- # ==== Input
356
- # [method_name : String] The name of the method.
357
- #
358
- # This value may be a string or a symbol.
359
- # [class_name : String : @class.name] The name of the class that the method
360
- # should have been invoked from.
361
- def method_called?(method_name, class_name = @class.name)
362
- !@stack_trace.index(
363
- {:method => method_name.to_sym, :class => class_name}).nil?
364
- end
365
-
366
309
  # Set the application state to alive.
367
310
  def reset_app_state
368
- TestInternals::AppState.state = :alive unless TestInternals::AppState.alive
311
+ AppState.state = :alive unless AppState.alive
369
312
  end
370
313
 
371
314
  # Resets the trace arrays.
@@ -387,14 +330,6 @@ Test::Unit::TestCase.class_eval do
387
330
  # Assertions.
388
331
  ############################################################################
389
332
 
390
- # Asserts that a value is equal to false.
391
- # ==== Input
392
- # [value : Any] The value to check for equality against false.
393
- # [message : String : nil] The message to display if the value is not false.
394
- def assert_false(value, message = nil)
395
- assert_equal false, value, message
396
- end
397
-
398
333
  # Asserts that a value is equal to true.
399
334
  # ==== Input
400
335
  # [value : Any] The value to check for equality against true.
@@ -403,6 +338,14 @@ Test::Unit::TestCase.class_eval do
403
338
  assert_equal true, value, message
404
339
  end
405
340
 
341
+ # Asserts that a value is equal to false.
342
+ # ==== Input
343
+ # [value : Any] The value to check for equality against false.
344
+ # [message : String : nil] The message to display if the value is not false.
345
+ def assert_false(value, message = nil)
346
+ assert_equal false, value, message
347
+ end
348
+
406
349
  # Asserts that the negation of a value is true.
407
350
  # ==== Input
408
351
  # [value : Any] The value which will be negated and then asserted.
@@ -513,39 +456,250 @@ Test::Unit::TestCase.class_eval do
513
456
  # Assertions - Application state.
514
457
  ############################################################################
515
458
 
516
- # Asserts that the application has been stopped.
459
+ # Asserts that the application is still running.
517
460
  # ==== Input
518
461
  # [message : String : nil] The message to show if the assertion fails.
519
- def assert_dead(message = nil)
520
- message = "#{@class} was not stopped as expected" if message.nil?
462
+ def assert_alive(message = nil)
463
+ message = "#{@class} is not running as expected" if message.nil?
521
464
 
522
465
  # Hold the state in a local variable so that the state can be reset
523
466
  # prior to the assertion.
524
- dead = TestInternals::AppState.dead
467
+ alive = AppState.alive
525
468
 
526
469
  # Reset the application state so that later tests are not adversely
527
470
  # affected if this assertion fails, which otherwise could leave
528
471
  # the application in an incorrect state.
529
472
  reset_app_state
530
473
 
531
- assert_true dead, message
474
+ assert alive, message
532
475
  end
533
476
 
534
- # Asserts that the application is still running.
477
+ # Asserts that the application has been stopped.
535
478
  # ==== Input
536
479
  # [message : String : nil] The message to show if the assertion fails.
537
- def assert_alive(message = nil)
538
- message = "#{@class} is not running as expected" if message.nil?
480
+ def assert_dead(message = nil)
481
+ message = "#{@class} was not stopped as expected" if message.nil?
539
482
 
540
483
  # Hold the state in a local variable so that the state can be reset
541
484
  # prior to the assertion.
542
- alive = TestInternals::AppState.alive
485
+ dead = AppState.dead
543
486
 
544
487
  # Reset the application state so that later tests are not adversely
545
488
  # affected if this assertion fails, which otherwise could leave
546
489
  # the application in an incorrect state.
547
490
  reset_app_state
548
491
 
549
- assert_true alive, message
492
+ assert dead, message
493
+ end
494
+
495
+ ############################################################################
496
+ private
497
+ ############################################################################
498
+
499
+ # Private methods are intended for use in this class only.
500
+ # They are NOT intended for use in sub-classes.
501
+
502
+ ############################################################################
503
+ # @obj and @class-related methods
504
+ ############################################################################
505
+
506
+ # Indicates whether a new object instance should (and can)
507
+ # be created during initialization.
508
+ # ==== Output
509
+ # [Boolean] Whether a new object should (and can) be created.
510
+ def new_object_on_init?
511
+ @init_object && @class.respond_to?(:new)
512
+ end
513
+
514
+ # Sends a method to the specified object along with parameters.
515
+ # ==== Input
516
+ # [object : Any] The object to send the method to.
517
+ # [method : Symbol, String] The method to call.
518
+ # [*args : Array] The parameters to pass to the method.
519
+ def send_to(object, method, *args)
520
+ result = nil
521
+
522
+ if args.length == 0
523
+ wrap_output { result = object.send(method.to_sym) }
524
+ else
525
+ wrap_output { result = object.send(method.to_sym, *args) }
526
+ end
527
+
528
+ return result
529
+ end
530
+
531
+ ############################################################################
532
+ # Monkey patching methods for the class being tested.
533
+ ############################################################################
534
+
535
+ # Monkey patch the class's initializer to enable tracing
536
+ # with parameters and results.
537
+ def set_initializer
538
+ @class.class_eval do
539
+ attr_accessor :trace
540
+
541
+ alias :test_case_initialize :initialize
542
+ def initialize(*args)
543
+ @trace = []
544
+ result = test_case_initialize(*args)
545
+ return result
546
+ end
547
+ end
548
+ end
549
+
550
+ # Loop through the instance methods, calling set_instance_methods for each.
551
+ def set_instance_method_wrappers
552
+ [
553
+ :public_instance_methods,
554
+ :protected_instance_methods,
555
+ :private_instance_methods,
556
+ ].each do |method_id|
557
+
558
+ scope = method_id.to_s.gsub(/_.*/, '')
559
+
560
+ set_instance_methods(@class.send(method_id) -
561
+ @class.superclass.send(method_id), scope)
562
+ end
563
+
564
+ # If this is not at the end, the loop will attempt to do it's thing
565
+ # with the constructor created in this method, which is not necessary.
566
+ set_initializer
567
+ end
568
+
569
+ # Loop through the list of methods that are passed in,
570
+ # creating a wrapper method that enables tracing.
571
+ #
572
+ # Tracing data includes method name, parameters, and result.
573
+ # ==== Input
574
+ # [method_list : Array] A list of methods that will have wrapping functions
575
+ # created to enable tracing.
576
+ # [scope : String] The scope of the original function.
577
+ def set_instance_methods(method_list, scope)
578
+ method_list.each do |method_id|
579
+ # Setters and methods that accept blocks do not appear to work.
580
+ next if method_id =~ /=/ or method_id =~ /wrap_output/
581
+
582
+ # Build the method.
583
+ new_method = <<-DOC
584
+ alias :test_case_#{method_id} :#{method_id}
585
+ def #{method_id}(*args)
586
+ result = test_case_#{method_id}(*args)
587
+ @trace << {
588
+ :method => '#{method_id}',
589
+ :args => args,
590
+ :result => result
591
+ }
592
+ return result
593
+ end
594
+ #{scope} :#{method_id}
595
+ DOC
596
+
597
+ # Add the method to the class.
598
+ @class.class_eval do
599
+ eval(new_method)
600
+ end
601
+ end
602
+ end
603
+
604
+ # Expose the private methods that are passed in. New methods will be created
605
+ # with the old method name followed by '_public_test'. If the original
606
+ # method contained a '?', it will be removed in the new method.
607
+ # ==== Input
608
+ # [type : Symbol] Indicates whether to handle instance or class methods.
609
+ #
610
+ # Only :class and :instance are supported.
611
+ # [methods : Array] An array of the methods to expose.
612
+ def expose_private_methods(type, methods)
613
+ # Get the text that the method should be wrapped in.
614
+ method_wrapper = wrapper(type)
615
+
616
+ # Loop through the methods.
617
+ methods.each do |method|
618
+ # Remove ?s.
619
+ new_method = method.to_s.gsub(/\?/, '')
620
+
621
+ # This is the new method.
622
+ new_method = <<-DOC
623
+ def #{new_method}_public_test(*args)
624
+ #{method}(*args)
625
+ end
626
+ DOC
627
+
628
+ # Add the wrapping text.
629
+ new_method = method_wrapper % [new_method]
630
+
631
+ # Add the method to the class.
632
+ @class.class_eval do
633
+ eval(new_method)
634
+ end
635
+ end
636
+ end
637
+
638
+ # Expose the variables.
639
+ #
640
+ # New methods will be created (a getter and a setter) for each variable.
641
+ #
642
+ # Regardless of the type of variable, these methods are only available
643
+ # via an instance.
644
+ # ==== Input
645
+ # [variables : Array] An array of variables to expose.
646
+ def expose_variables(variables)
647
+ # Get the text that the methods should be wrapped in.
648
+ var_wrapper = wrapper(:instance)
649
+
650
+ # Loop through the variables
651
+ variables.each do |var|
652
+ # Remove any @s.
653
+ new_method = var.to_s.gsub(/@/, '')
654
+
655
+ # These are the new getter and setters.
656
+ new_method = <<-DOC
657
+ def #{new_method}_variable_method
658
+ #{var}
659
+ end
660
+
661
+ def #{new_method}_variable_method=(value)
662
+ #{var} = value
663
+ end
664
+ DOC
665
+
666
+ # Add the wrapping text.
667
+ new_method = var_wrapper % [new_method]
668
+
669
+ # Add the methods to the class.
670
+ @class.class_eval do
671
+ eval(new_method)
672
+ end
673
+ end
674
+ end
675
+
676
+ # Returns the wrapping text for the specified type of method.
677
+ # ==== Input
678
+ # [type : Symbol] Indicates whether to handle instance or class methods.
679
+ #
680
+ # Only :class & :instance are supported.
681
+ # ==== Output
682
+ # [String] The text that the specified type of method should be wrapped in.
683
+ def wrapper(type)
684
+ case type
685
+ when :class then 'class << self;%s;end'
686
+ when :instance then '%s'
687
+ end
688
+ end
689
+
690
+ ############################################################################
691
+ # Support methods.
692
+ ############################################################################
693
+
694
+ # Indicates whether the specified method has been called on a given class.
695
+ # ==== Input
696
+ # [method_name : String] The name of the method.
697
+ #
698
+ # This value may be a string or a symbol.
699
+ # [class_name : String : @class.name] The name of the class that the method
700
+ # should have been invoked from.
701
+ def method_called?(method_name, class_name = @class.name)
702
+ !@stack_trace.index(
703
+ {:method => method_name.to_sym, :class => class_name}).nil?
550
704
  end
551
705
  end
@@ -1,5 +1,4 @@
1
- # This file contains the constant that is used to determine whether the
2
- # application is still running or not.
1
+ # This file contains the main part of the module for this gem.
3
2
 
4
3
  #--
5
4
  ################################################################################
@@ -33,7 +32,8 @@
33
32
  ################################################################################
34
33
  #++
35
34
 
35
+ # Main module for this gem.
36
36
  module TestInternals
37
- # This constant is used to track whether the application is still running.
38
- AppState = AppMode.new(:alive, [:alive, :dead])
37
+ # This constant is used to indicate whether the application has been stopped.
38
+ AppState = StateManager.new(:alive, [:alive, :dead])
39
39
  end
@@ -1,8 +1,7 @@
1
1
  gem_name = File.basename(__FILE__, '.rb')
2
2
 
3
- require 'app_mode'
4
3
  require 'test/unit'
4
+ require 'app_mode'
5
5
 
6
- require_relative File.join(gem_name, 'app_state')
7
- require_relative File.join(gem_name, 'kernel')
6
+ require_relative File.join(gem_name, gem_name)
8
7
  require_relative File.join(gem_name, 'test_case')
@@ -1,19 +1,22 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'test_internals'
3
- s.version = '0.0.2'
3
+ s.version = '1.0.0'
4
4
 
5
5
  s.summary = 'Allows tests to check the stack trace, ' +
6
6
  'parameters, private methods, and class variables.'
7
- s.description = 'TestInternals patches Test::Unit::TestCase to allow ' +
8
- 'testing of private methods, as well as variables. The stack trace ' +
9
- 'is also available, including the ability to check that specific ' +
10
- 'parameters were sent to a method.'
7
+
8
+ s.description = %Q{
9
+ TestInternals patches Test::Unit::TestCase to allow
10
+ testing of private methods, as well as variables. The stack trace
11
+ is also available, including the ability to check that specific
12
+ parameters were sent to a method. This results in cotton candy goodness for all.
13
+ }.strip
11
14
 
12
15
  s.author = 'Travis Herrick'
13
16
  s.email = 'tthetoad@gmail.com'
14
17
  s.homepage = 'http://www.bitbucket.org/ToadJamb/gems_test_internals'
15
18
 
16
- s.license = 'GPLV3'
19
+ s.license = 'GPLv3'
17
20
 
18
21
  s.extra_rdoc_files << 'README'
19
22
 
@@ -21,7 +24,7 @@ Gem::Specification.new do |s|
21
24
  s.files = Dir['lib/**/*.rb', '*']
22
25
  s.test_files = Dir['test/**/*.rb']
23
26
 
24
- s.add_dependency 'app_mode', '~> 0.0.1'
27
+ s.add_dependency 'app_mode', '~> 1.0.0'
25
28
 
26
29
  s.add_development_dependency 'rake_tasks', '~> 0.0.1'
27
30
 
metadata CHANGED
@@ -3,10 +3,10 @@ name: test_internals
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
+ - 1
6
7
  - 0
7
8
  - 0
8
- - 2
9
- version: 0.0.2
9
+ version: 1.0.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Travis Herrick
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-08-08 00:00:00 -04:00
17
+ date: 2011-08-15 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -25,10 +25,10 @@ dependencies:
25
25
  - - ~>
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
+ - 1
28
29
  - 0
29
30
  - 0
30
- - 1
31
- version: 0.0.1
31
+ version: 1.0.0
32
32
  type: :runtime
33
33
  prerelease: false
34
34
  version_requirements: *id001
@@ -47,7 +47,11 @@ dependencies:
47
47
  type: :development
48
48
  prerelease: false
49
49
  version_requirements: *id002
50
- description: TestInternals patches Test::Unit::TestCase to allow testing of private methods, as well as variables. The stack trace is also available, including the ability to check that specific parameters were sent to a method.
50
+ description: |-
51
+ TestInternals patches Test::Unit::TestCase to allow
52
+ testing of private methods, as well as variables. The stack trace
53
+ is also available, including the ability to check that specific
54
+ parameters were sent to a method. This results in cotton candy goodness for all.
51
55
  email: tthetoad@gmail.com
52
56
  executables: []
53
57
 
@@ -56,19 +60,18 @@ extensions: []
56
60
  extra_rdoc_files:
57
61
  - README
58
62
  files:
59
- - lib/test_internals/test_case.rb
60
- - lib/test_internals/app_state.rb
61
- - lib/test_internals/kernel.rb
62
63
  - lib/test_internals.rb
64
+ - lib/test_internals/test_case.rb
65
+ - lib/test_internals/test_internals.rb
63
66
  - Gemfile.lock
64
67
  - Gemfile
65
- - rakefile
66
68
  - README
69
+ - rakefile
67
70
  - test_internals.gemspec
68
71
  has_rdoc: true
69
72
  homepage: http://www.bitbucket.org/ToadJamb/gems_test_internals
70
73
  licenses:
71
- - GPLV3
74
+ - GPLv3
72
75
  post_install_message:
73
76
  rdoc_options: []
74
77
 
@@ -79,7 +82,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
82
  requirements:
80
83
  - - ">="
81
84
  - !ruby/object:Gem::Version
82
- hash: -2525836242587382346
85
+ hash: 2800249786482312969
83
86
  segments:
84
87
  - 0
85
88
  version: "0"
@@ -1,42 +0,0 @@
1
- # This file contains a monkey patch of Kernel functions for use during testing.
2
-
3
- #--
4
- ################################################################################
5
- # Copyright (C) 2011 Travis Herrick #
6
- ################################################################################
7
- # #
8
- # \v^V,^!v\^/ #
9
- # ~% %~ #
10
- # { _ _ } #
11
- # ( * - ) #
12
- # | / | #
13
- # \ _, / #
14
- # \__.__/ #
15
- # #
16
- ################################################################################
17
- # This program is free software: you can redistribute it #
18
- # and/or modify it under the terms of the GNU General Public License #
19
- # as published by the Free Software Foundation, #
20
- # either version 3 of the License, or (at your option) any later version. #
21
- # #
22
- # Commercial licensing may be available for a fee under a different license. #
23
- ################################################################################
24
- # This program is distributed in the hope that it will be useful, #
25
- # but WITHOUT ANY WARRANTY; #
26
- # without even the implied warranty of MERCHANTABILITY #
27
- # or FITNESS FOR A PARTICULAR PURPOSE. #
28
- # See the GNU General Public License for more details. #
29
- # #
30
- # You should have received a copy of the GNU General Public License #
31
- # along with this program. If not, see <http://www.gnu.org/licenses/>. #
32
- ################################################################################
33
- #++
34
-
35
- # Monkey patch Kernel classes and functions for testing.
36
- module Kernel
37
- # Patch exit so that it sets a flag rather than ends the application.
38
- # (A call to exit will cause testing to stop otherwise).
39
- def exit(*args)
40
- TestInternals::AppState.state = :dead
41
- end
42
- end