test_internals 0.0.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/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