tap 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (185) hide show
  1. data/Basic Overview +151 -0
  2. data/Command Reference +99 -0
  3. data/History +24 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README +29 -57
  6. data/Rakefile +30 -37
  7. data/Tutorial +243 -191
  8. data/bin/tap +66 -35
  9. data/lib/tap.rb +47 -29
  10. data/lib/tap/app.rb +700 -342
  11. data/lib/tap/{script → cmd}/console.rb +0 -0
  12. data/lib/tap/{script → cmd}/destroy.rb +0 -0
  13. data/lib/tap/{script → cmd}/generate.rb +0 -0
  14. data/lib/tap/cmd/run.rb +156 -0
  15. data/lib/tap/constants.rb +4 -0
  16. data/lib/tap/dump.rb +57 -0
  17. data/lib/tap/env.rb +316 -0
  18. data/lib/tap/file_task.rb +106 -109
  19. data/lib/tap/generator.rb +4 -1
  20. data/lib/tap/generator/generators/command/USAGE +6 -0
  21. data/lib/tap/generator/generators/command/command_generator.rb +17 -0
  22. data/lib/tap/generator/generators/{script/templates/script.erb → command/templates/command.erb} +10 -10
  23. data/lib/tap/generator/generators/config/USAGE +21 -0
  24. data/lib/tap/generator/generators/config/config_generator.rb +17 -7
  25. data/lib/tap/generator/generators/file_task/USAGE +3 -0
  26. data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -0
  27. data/lib/tap/generator/generators/file_task/templates/file.txt +2 -0
  28. data/lib/tap/generator/generators/file_task/templates/file.yml +3 -0
  29. data/lib/tap/generator/generators/file_task/templates/task.erb +26 -20
  30. data/lib/tap/generator/generators/file_task/templates/test.erb +20 -10
  31. data/lib/tap/generator/generators/generator/generator_generator.rb +1 -1
  32. data/lib/tap/generator/generators/generator/templates/generator.erb +21 -12
  33. data/lib/tap/generator/generators/root/templates/Rakefile +33 -24
  34. data/lib/tap/generator/generators/root/templates/tap.yml +28 -31
  35. data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +1 -0
  36. data/lib/tap/generator/generators/task/USAGE +3 -0
  37. data/lib/tap/generator/generators/task/task_generator.rb +18 -5
  38. data/lib/tap/generator/generators/task/templates/task.erb +7 -12
  39. data/lib/tap/generator/generators/task/templates/test.erb +10 -11
  40. data/lib/tap/generator/generators/workflow/templates/task.erb +1 -1
  41. data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
  42. data/lib/tap/patches/rake/rake_test_loader.rb +8 -0
  43. data/lib/tap/patches/rake/testtask.rb +55 -0
  44. data/lib/tap/patches/ruby19/backtrace_filter.rb +51 -0
  45. data/lib/tap/patches/ruby19/parsedate.rb +16 -0
  46. data/lib/tap/root.rb +172 -67
  47. data/lib/tap/script.rb +70 -336
  48. data/lib/tap/support/aggregator.rb +55 -0
  49. data/lib/tap/support/audit.rb +281 -280
  50. data/lib/tap/support/batchable.rb +59 -0
  51. data/lib/tap/support/class_configuration.rb +279 -0
  52. data/lib/tap/support/configurable.rb +92 -0
  53. data/lib/tap/support/configurable_methods.rb +296 -0
  54. data/lib/tap/support/executable.rb +98 -0
  55. data/lib/tap/support/executable_queue.rb +82 -0
  56. data/lib/tap/support/logger.rb +9 -15
  57. data/lib/tap/support/rake.rb +43 -54
  58. data/lib/tap/support/run_error.rb +32 -13
  59. data/lib/tap/support/shell_utils.rb +47 -0
  60. data/lib/tap/support/tdoc.rb +9 -8
  61. data/lib/tap/support/tdoc/config_attr.rb +40 -16
  62. data/lib/tap/support/validation.rb +77 -0
  63. data/lib/tap/support/versions.rb +36 -36
  64. data/lib/tap/task.rb +276 -482
  65. data/lib/tap/test.rb +20 -261
  66. data/lib/tap/test/env_vars.rb +7 -5
  67. data/lib/tap/test/file_methods.rb +126 -121
  68. data/lib/tap/test/subset_methods.rb +86 -45
  69. data/lib/tap/test/tap_methods.rb +271 -0
  70. data/lib/tap/workflow.rb +174 -46
  71. data/test/app/config/another/task.yml +1 -0
  72. data/test/app/config/erb.yml +2 -1
  73. data/test/app/config/some/task.yml +1 -0
  74. data/test/app/config/template.yml +2 -6
  75. data/test/app_test.rb +1241 -1008
  76. data/test/env/test_configure/recurse_a.yml +2 -0
  77. data/test/env/test_configure/recurse_b.yml +2 -0
  78. data/test/env/test_configure/tap.yml +23 -0
  79. data/test/env/test_load_env_config/dir/tap.yml +3 -0
  80. data/test/env/test_load_env_config/recurse_a.yml +2 -0
  81. data/test/env/test_load_env_config/recurse_b.yml +2 -0
  82. data/test/env/test_load_env_config/tap.yml +3 -0
  83. data/test/env_test.rb +198 -0
  84. data/test/file_task_test.rb +70 -53
  85. data/{lib/tap/generator/generators/package/USAGE → test/root/file.txt} +0 -0
  86. data/test/root_test.rb +621 -454
  87. data/test/script_test.rb +38 -174
  88. data/test/support/aggregator_test.rb +99 -0
  89. data/test/support/audit_test.rb +409 -416
  90. data/test/support/batchable_test.rb +74 -0
  91. data/test/support/{task_configuration_test.rb → class_configuration_test.rb} +106 -47
  92. data/test/{task/config/overriding.yml → support/configurable/config/configured.yml} +0 -0
  93. data/test/support/configurable_test.rb +295 -0
  94. data/test/support/executable_queue_test.rb +103 -0
  95. data/test/support/executable_test.rb +38 -0
  96. data/test/support/logger_test.rb +17 -17
  97. data/test/support/rake_test.rb +4 -2
  98. data/test/support/shell_utils_test.rb +24 -0
  99. data/test/support/tdoc_test.rb +265 -258
  100. data/test/support/validation_test.rb +54 -0
  101. data/test/support/versions_test.rb +38 -38
  102. data/test/tap_test_helper.rb +19 -5
  103. data/test/tap_test_suite.rb +5 -2
  104. data/test/task_base_test.rb +13 -104
  105. data/test/task_syntax_test.rb +300 -0
  106. data/test/task_test.rb +258 -381
  107. data/test/test/env_vars_test.rb +40 -40
  108. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/one.txt +0 -0
  109. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/two.txt +0 -0
  110. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/one.txt +0 -0
  111. data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/two.txt +0 -0
  112. data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/one.txt +0 -0
  113. data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/two.txt +0 -0
  114. data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +1 -0
  115. data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_different_content}/expected/two.txt +0 -0
  116. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +1 -0
  117. data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +1 -0
  118. data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_missing_expected_file}/expected/one.txt +0 -0
  119. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +1 -0
  120. data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +1 -0
  121. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +1 -0
  122. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +1 -0
  123. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +1 -0
  124. data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +1 -0
  125. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +1 -0
  126. data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +1 -0
  127. data/test/test/file_methods_doc/test_sub/expected/one.txt +1 -0
  128. data/test/test/file_methods_doc/test_sub/expected/two.txt +1 -0
  129. data/test/test/file_methods_doc/test_sub/input/one.txt +1 -0
  130. data/test/test/file_methods_doc/test_sub/input/two.txt +1 -0
  131. data/test/test/file_methods_doc_test.rb +29 -0
  132. data/test/test/file_methods_test.rb +214 -143
  133. data/test/test/subset_methods_test.rb +111 -115
  134. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/a.txt +0 -0
  135. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/b.txt +0 -0
  136. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/a.txt +0 -0
  137. data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/b.txt +0 -0
  138. data/test/test/tap_methods_test.rb +399 -0
  139. data/test/workflow_test.rb +101 -91
  140. metadata +86 -70
  141. data/lib/tap/generator/generators/package/package_generator.rb +0 -38
  142. data/lib/tap/generator/generators/package/templates/package.erb +0 -186
  143. data/lib/tap/generator/generators/script/USAGE +0 -0
  144. data/lib/tap/generator/generators/script/script_generator.rb +0 -17
  145. data/lib/tap/script/run.rb +0 -154
  146. data/lib/tap/support/batch_queue.rb +0 -162
  147. data/lib/tap/support/combinator.rb +0 -114
  148. data/lib/tap/support/task_configuration.rb +0 -169
  149. data/lib/tap/support/template.rb +0 -81
  150. data/lib/tap/support/templater.rb +0 -155
  151. data/lib/tap/version.rb +0 -4
  152. data/test/app/config/addition_template.yml +0 -6
  153. data/test/app_class_test.rb +0 -33
  154. data/test/check/binding_eval.rb +0 -23
  155. data/test/check/define_method_check.rb +0 -22
  156. data/test/check/dependencies_check.rb +0 -175
  157. data/test/check/inheritance_check.rb +0 -22
  158. data/test/support/batch_queue_test.rb +0 -320
  159. data/test/support/combinator_test.rb +0 -249
  160. data/test/support/template_test.rb +0 -122
  161. data/test/support/templater/erb.txt +0 -2
  162. data/test/support/templater/erb.yml +0 -2
  163. data/test/support/templater/somefile.txt +0 -2
  164. data/test/support/templater_test.rb +0 -192
  165. data/test/task/config/template.yml +0 -4
  166. data/test/task_class_test.rb +0 -170
  167. data/test/task_execute_test.rb +0 -262
  168. data/test/test/file_methods/test_assert_expected/expected/file.txt +0 -1
  169. data/test/test/file_methods/test_assert_expected/expected/folder/file.txt +0 -1
  170. data/test/test/file_methods/test_assert_expected/input/file.txt +0 -1
  171. data/test/test/file_methods/test_assert_expected/input/folder/file.txt +0 -1
  172. data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
  173. data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
  174. data/test/test/file_methods/test_file_compare/expected/output_1.txt +0 -3
  175. data/test/test/file_methods/test_file_compare/expected/output_2.txt +0 -1
  176. data/test/test/file_methods/test_file_compare/input/input_1.txt +0 -3
  177. data/test/test/file_methods/test_file_compare/input/input_2.txt +0 -3
  178. data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
  179. data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
  180. data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
  181. data/test/test/file_methods/test_yml_compare/expected/output_1.yml +0 -6
  182. data/test/test/file_methods/test_yml_compare/expected/output_2.yml +0 -6
  183. data/test/test/file_methods/test_yml_compare/input/input_1.yml +0 -4
  184. data/test/test/file_methods/test_yml_compare/input/input_2.yml +0 -4
  185. data/test/test_test.rb +0 -373
@@ -5,7 +5,6 @@ require 'tap/test/env_vars'
5
5
 
6
6
  module Test # :nodoc:
7
7
  module Unit # :nodoc:
8
- # Methods extending TestCase. See the TestTutorial for more information.
9
8
  class TestCase
10
9
  class << self
11
10
  include Tap::Test::EnvVars
@@ -16,7 +15,9 @@ module Test # :nodoc:
16
15
  subclass_conditions = conditions.inject({}) do |memo, (key, value)|
17
16
  memo.update(key => (value.dup rescue value))
18
17
  end
19
- subclass.instance_variable_set("@conditions", subclass_conditions)
18
+ subclass.instance_variable_set(:@conditions, subclass_conditions)
19
+ subclass.instance_variable_set(:@run_test_suite, nil)
20
+ subclass.instance_variable_set(:@skip_messages, [])
20
21
 
21
22
  # subclass_inputs = prompt_inputs.inject({}) do |memo, (key, value)|
22
23
  # memo.update(key => (value.dup rescue value))
@@ -107,8 +108,8 @@ module Test # :nodoc:
107
108
  # true if no platforms are specified.
108
109
  #
109
110
  # Some common platforms:
110
- # - mswin:: Windows
111
- # - darwin:: Mac
111
+ # mswin Windows
112
+ # darwin Mac
112
113
  def match_platform?(*platforms)
113
114
  platforms.each do |platform|
114
115
  platform.to_s =~ /^(non_)?(.*)/
@@ -139,11 +140,11 @@ module Test # :nodoc:
139
140
  # Causes a test suite to be skipped. If a message is given, it will
140
141
  # print and notify the user the test suite has been skipped.
141
142
  def skip_test(msg=nil)
142
- @run_test_suite = false
143
+ self.run_test_suite = false
143
144
 
144
145
  # experimental -- perhaps use this so that a test can be skipped
145
146
  # for multiple reasons?
146
- (@skip_messages ||= []) << msg unless msg.nil?
147
+ @skip_messages << msg unless msg.nil?
147
148
  end
148
149
 
149
150
  alias :original_suite :suite
@@ -153,7 +154,6 @@ module Test # :nodoc:
153
154
  if run_test_suite?
154
155
  original_suite
155
156
  else
156
- @skip_messages ||= []
157
157
  puts "Skipping #{name}: #{@skip_messages.join(', ')}" unless @skip_messages.empty?
158
158
  Test::Unit::TestSuite.new(name)
159
159
  end
@@ -169,7 +169,7 @@ module Tap
169
169
  # Ideally you always run all of your tests and they all run and pass everywhere. In
170
170
  # practice it's useful to suppress the execution of some tests -- long running tests,
171
171
  # tests specific for a given platform, or tests that depend on some condition, such
172
- # as the version of some third-party software your code interacts with.
172
+ # as the version of some optional third-party software your code interacts with.
173
173
  #
174
174
  # SubsetMethods extends TestCase with methods for defining conditions that can be
175
175
  # used to conditionally perform some action, or skip a test suite entirely. When
@@ -185,54 +185,64 @@ module Tap
185
185
  # condition(:non_windows) { match_platform?('non_mswin') }
186
186
  # end
187
187
  #
188
- # class AfterHoursTest < Test::Unit::TestCase
189
- # # only true between 6pm and 6am
190
- # # (maybe you're not allowed to tie up a computer until after hours)
191
- # condition(:afterhours) { Time.now > 18 || Time.now < 6 }
192
- #
193
- # skip_test unless satisfied?(:windows, :afterhours)
188
+ # class WindowsOnlyTest < Test::Unit::TestCase
189
+ # skip_test unless satisfied?(:windows)
194
190
  # end
195
191
  #
196
- # AfterHoursTest will only run between the hours of 6pm and 6am, on a Windows platform.
197
- # These conditions can be used in specific tests, when only some tests need to be skipped.
192
+ # WindowsOnlyTest will only run on a Windows platform. These conditions can be used
193
+ # in specific tests, when only some tests need to be skipped.
198
194
  #
199
195
  # class RunOnlyAFewTest < Test::Unit::TestCase
200
196
  # include SubsetMethods
201
- # include Benchmark
202
197
  #
203
198
  # def test_runs_all_the_time
204
199
  # assert true
205
200
  # end
206
201
  #
207
- # def test_runs_only_if_afterhours_condition_is_true
208
- # condition_test(:afterhours) do
209
- # ...
202
+ # def test_runs_only_if_non_windows_condition_is_true
203
+ # condition_test(:non_windows) { assert true }
210
204
  # end
211
205
  # end
212
206
  #
213
- # def test_runs_only_when_EXTENDED_is_true
214
- # extended_test do
215
- # ...
216
- # end
207
+ # def test_runs_only_when_ENV_variable_EXTENDED_is_true
208
+ # extended_test { assert true }
217
209
  # end
218
210
  #
219
- # def test_runs_only_when_BENCHMARK_is_true
211
+ # def test_runs_only_when_ENV_variable_BENCHMARK_is_true
220
212
  # benchmark_test do |x|
221
213
  # x.report("init speed") { 10000.times { Object.new } }
222
214
  # end
223
215
  # end
216
+ #
217
+ # def test_runs_only_when_ENV_variable_CUSTOM_is_true
218
+ # subset_test('CUSTOM') { assert true }
219
+ # end
224
220
  # end
225
221
  #
226
- # In the example, EXTENDED and BENCHMARK refer to environment (ENV) variables.
227
- # ENV variables can be set from the command line like so:
222
+ # In the example, the ENV variables EXTENDED, BENCHMARK, and CUSTOM act as flags
223
+ # to run specific tests. If you're running your test using Rake, ENV variables
224
+ # can be set from the command line like so:
228
225
  #
229
- # % tap run test extended=true
230
- # % tap run test BENCHMARK=true
226
+ # % rake test EXTENDED=true
227
+ # % rake test BENCHMARK=true
231
228
  #
232
- # In so far as SubsetMethods is concerned, the environment variables are case-insensitive.
233
- # To run all tests that get switched using an environment variable, set ALL=true.
229
+ # Since tap can run rake tasks as well, these are equivalent:
234
230
  #
235
- # == Class Methods
231
+ # % tap run test EXTENDED=true
232
+ # % tap run test BENCHMARK=true
233
+ #
234
+ # In so far as SubsetMethods is concerned, the environment variables are
235
+ # case-insensitive. As in the example, additional ENV-variable-dependent
236
+ # tests can be defined using the subset_test method. To run all tests that
237
+ # get switched using an environment variable, set ALL=true.
238
+ #
239
+ # # also runs benchmark tests
240
+ # % tap run test BenchMark=true
241
+ #
242
+ # # runs all tests
243
+ # % tap run test all=true
244
+ #
245
+ # === Class Methods
236
246
  #
237
247
  # See Test::Unit::TestCase for documentation of the class methods added by SubsetMethods
238
248
  module SubsetMethods
@@ -247,13 +257,14 @@ module Tap
247
257
  self.class.run_subset?(type)
248
258
  end
249
259
 
250
- # Returns true if the pretty-print string for obj matches the regexp specified in env_var(type).
251
- # Returns the default value if 'ALL' is specified in ENV or type is not specified in ENV.
252
- def match_regexp?(type, obj, default=true)
260
+ # Returns true if the input string matches the regexp specified in
261
+ # env_var(type). Returns the default value if 'ALL' is specified in
262
+ # ENV or type is not specified in ENV.
263
+ def match_regexp?(type, str, default=true)
253
264
  return true if env_true?("ALL")
254
265
  return default unless env(type)
255
266
 
256
- PP.singleline_pp(obj, '') =~ Regexp.new(env(type)) ? true : false
267
+ str =~ Regexp.new(env(type)) ? true : false
257
268
  end
258
269
 
259
270
  # Platform-specific test. Useful for specifying test that should only
@@ -298,16 +309,47 @@ module Tap
298
309
  end
299
310
 
300
311
  # Basic method for a subset test. The provided block will run if:
301
- # - The subset type or 'ALL' is specified in ENV
302
- # - The calling method matches the regexp provided in the "TYPE_TEST" ENV variable
312
+ # - The subset type is specified in ENV
313
+ # - The subset 'ALL' is specified in ENV
314
+ # - The test method name matches the regexp provided in the <TYPE>_TEST ENV variable
303
315
  #
304
- # Otherwise the block will be skipped and +skip+ will be printed. By default skip
305
- # is the first letter of +type+.
316
+ # Otherwise the block will be skipped and +skip+ will be printed in the test output.
317
+ # By default skip is the first letter of +type+.
318
+ #
319
+ # For example, with these methods:
320
+ #
321
+ # def test_one
322
+ # subset_test('CUSTOM') { assert true }
323
+ # end
324
+ #
325
+ # def test_two
326
+ # subset_test('CUSTOM') { assert true }
327
+ # end
328
+ #
329
+ # Condition Tests that get run
330
+ # ENV['ALL']=true test_one, test_two
331
+ # ENV['CUSTOM']=true test_one, test_two
332
+ # ENV['CUSTOM_TEST']=test_ test_one, test_two
333
+ # ENV['CUSTOM_TEST']=test_one test_one
334
+ # ENV['CUSTOM']=nil no tests get run
335
+ #
336
+ # If you're running your tests with Rake, ENV variables can be set from the
337
+ # command line, so you might use these command line statements:
338
+ #
339
+ # # all tests
340
+ # % rake test all=true
341
+ #
342
+ # # custom subset tests
343
+ # % rake test custom=true
344
+ #
345
+ # # just test_one
346
+ # % rake test custom_test=test_one
347
+ #
306
348
  def subset_test(type, skip=type[0..0].downcase)
307
349
  type = type.upcase
308
350
  type_test = "#{type}_TEST"
309
351
  if run_subset?(type) || env(type_test)
310
- if match_regexp?(type_test, method_name)
352
+ if match_regexp?(type_test, method_name.to_s)
311
353
  yield
312
354
  else
313
355
  print skip
@@ -328,9 +370,8 @@ module Tap
328
370
  end
329
371
 
330
372
  # Declares a subset_test for the ENV variable 'BENCHMARK'. If run,
331
- # benchmark_test sets up benchmarking using the bm method using the
332
- # input length and block. As a result you MUST 'include Benchmark'
333
- # in the test class. Prints 'b' if the test is not run.
373
+ # benchmark_test sets up benchmarking using the Benchmark.bm method
374
+ # using the input length and block. Prints 'b' if the test is not run.
334
375
  #
335
376
  # include Benchmark
336
377
  # def test_speed
@@ -340,7 +381,7 @@ module Tap
340
381
  subset_test("BENCHMARK") do
341
382
  puts
342
383
  puts method_name
343
- bm(length, &block)
384
+ Benchmark.bm(length, &block)
344
385
  end
345
386
  end
346
387
 
@@ -0,0 +1,271 @@
1
+ require 'test/unit'
2
+ require 'tap/test/file_methods'
3
+ require 'tap/test/subset_methods'
4
+
5
+ module Test # :nodoc:
6
+ module Unit # :nodoc:
7
+ class TestCase
8
+ class << self
9
+ # Causes a unit test to act as a tap test -- resulting in the following:
10
+ # - setup using acts_as_file_test
11
+ # - inclusion of Tap::Test::SubsetMethods
12
+ # - inclusion of Tap::Test::InstanceMethods
13
+ #
14
+ # Note: Unless otherwise specified, <tt>acts_as_tap_test</tt> infers a root directory
15
+ # based on the calling file. Be sure to specify the root directory explicitly
16
+ # if you call acts_as_file_test from a file that is NOT meant to be test file.
17
+ def acts_as_tap_test(options={})
18
+ options = {:root => file_test_root}.merge(options.symbolize_keys)
19
+ acts_as_file_test(options)
20
+
21
+ include Tap::Test::SubsetMethods
22
+ include Tap::Test::TapMethods
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ module Tap
31
+ module Test
32
+
33
+ # Used during check_audit to hold the sources and values of an audit
34
+ # in the correct order. Oriented so that the next value to be checked
35
+ # is at the top of the stack. Used internally.
36
+ class AuditStack # :nodoc:
37
+ attr_reader :test
38
+
39
+ def initialize(test)
40
+ @test = test
41
+ @stack = []
42
+ end
43
+
44
+ def load_audit(values)
45
+ [values._sources, values._values].transpose.reverse_each do |sv|
46
+ load(*sv)
47
+ end
48
+ end
49
+
50
+ def load(source, value)
51
+ @stack.unshift [source, value]
52
+ end
53
+
54
+ def next
55
+ @stack.shift
56
+ end
57
+ end
58
+
59
+ # Tap-specific testing methods to help with testing Tasks, such as the
60
+ # checking of audits and test-specific modification of application
61
+ # configuration.
62
+ module TapMethods
63
+
64
+ # Returns the test-method-specific application.
65
+ attr_reader :app
66
+
67
+ # Setup creates a test-method-specific application that is initialized
68
+ # to the method_root, and uses the directories and absolute paths from
69
+ # trs (the test root structure, see Tap::Test::FileMethods).
70
+ #
71
+ # Also makes sure Tap::App.instance returns the test method app.
72
+ def setup
73
+ super
74
+ @app = Tap::App.new(
75
+ :root => method_root,
76
+ :directories => trs.directories,
77
+ :absolute_paths => trs.absolute_paths)
78
+ Tap::App.instance = @app
79
+ end
80
+
81
+ #
82
+ # audit test methods
83
+ #
84
+
85
+ # Used to define expected audits in Tap::Test::TapMethods#assert_audit_equal
86
+ class ExpAudit < Array
87
+ end
88
+
89
+ # Used to define merged audit trails in Tap::Test::TapMethods#assert_audit_equal
90
+ class ExpMerge < Array
91
+ end
92
+
93
+ # Asserts that an array of audits are all equal, basically feeding
94
+ # each pair of audits to assert_audit_equal.
95
+ def assert_audits_equal(expected, audits)
96
+ each_pair_with_index(expected, audits) do |exp, audit, index|
97
+ assert_audit_equal(exp, audit, [index])
98
+ end
99
+ end
100
+
101
+ # Asserts that an audit is as expected. The expected audit should
102
+ # be an ExpAudit (just a subclass of Array) that records the sources
103
+ # and the values at each step in the audit trail. Proc objects can
104
+ # be provided in place of expected records that are hard or impossible
105
+ # to provide directly; the Proc will be used to validate the actual
106
+ # record. Merges must be marked in the ExpAudit using ExpMerge.
107
+ #
108
+ # Simple assertion:
109
+ #
110
+ # a = Tap::Support::Audit.new
111
+ # a._record(:a, 'a')
112
+ # a._record(:b, 'b')
113
+ #
114
+ # e = ExpAudit[[:a, 'a'], [:b, 'b']]
115
+ # assert_audit_equal(e, a)
116
+ #
117
+ # Assertion validating a record with a Proc (any number of
118
+ # records can be validated with a Proc):
119
+ #
120
+ # a = Tap::Support::Audit.new
121
+ # a._record(:a, 'a')
122
+ # a._record(:b, 'b')
123
+ #
124
+ # e = ExpAudit[
125
+ # lambda {|source, value| source == :a && value == 'a'},
126
+ # [:b, 'b']]
127
+ # assert_audit_equal(e, a)
128
+ #
129
+ # Assertion with merge:
130
+ #
131
+ # a = Tap::Support::Audit.new
132
+ # a._record(:a, 'a')
133
+ # a._record(:b, 'b')
134
+ #
135
+ # b = Tap::Support::Audit.new
136
+ # b._record(:c, 'c')
137
+ # b._record(:d, 'd')
138
+ #
139
+ # c = Tap::Support::Audit.merge(a,b)
140
+ # c._record(:e, 'e')
141
+ # c._record(:f, 'f')
142
+ #
143
+ # ea = ExpAudit[[:a, "a"], [:b, "b"]]
144
+ # eb = ExpAudit[[:c, "c"], [:d, "d"]]
145
+ # e = ExpAudit[ExpMerge[ea, eb], [:e, "e"], [:f, "f"]]
146
+ #
147
+ # assert_audit_equal(e, c)
148
+ #
149
+ # When assert_audit_equal fails, a string of indicies is provided
150
+ # to help locate which record was unequal. For instance in the last
151
+ # example, say we used:
152
+ #
153
+ # ea = ExpAudit[[:a, "a"], [:b, "FLUNK"]]
154
+ # eb = ExpAudit[[:c, "c"], [:d, "d"]]
155
+ # e = ExpAudit[ExpMerge[ea, eb], [:e, "e"], [:f, "f"]]
156
+ #
157
+ # The failure message will read something like 'unequal record 0:0:1'
158
+ # indicating it was e[0][0][1] that failed. Working through it,
159
+ # remembering that ExpAudit and ExpMerge are just subclasses of
160
+ # Array:
161
+ #
162
+ # e # => ExpAudit[ExpMerge[ea, eb], [:e, "e"], [:f, "f"]]
163
+ # e[0] # => ExpMerge[ea, eb]
164
+ # e[0][0] # => ExpAudit[[:a, "a"], [:b, "FLUNK"]]
165
+ # e[0][0][1] # => [:b, "FLUNK"]
166
+ #
167
+ def assert_audit_equal(expected, audit, nesting=[])
168
+ actual = audit._collect_records {|source, value| [source, value]}
169
+ assert_audit_records_equal(expected, actual, nesting)
170
+ end
171
+
172
+ private
173
+
174
+ def assert_audit_records_equal(expected, actual, nesting=[])
175
+ assert_equal ExpAudit, expected.class
176
+ assert_equal expected.length, actual.length, "unequal number of records"
177
+
178
+ expected.each_with_index do |exp_record, i|
179
+ case exp_record
180
+ when ExpMerge
181
+ exp_record.each_with_index do |exp_audit, j|
182
+ assert_audit_records_equal(exp_audit, actual[i][j], nesting + [i,j])
183
+ end
184
+ when Proc
185
+ assert exp_record.call(*actual[i]), "unconfirmed record #{(nesting + [i]).join(':')}"
186
+ else
187
+ assert_equal exp_record, actual[i], "unequal record #{(nesting + [i]).join(':')}"
188
+ end
189
+ end
190
+ end
191
+
192
+ public
193
+
194
+ #
195
+ # application methods
196
+ #
197
+
198
+ # Applies the input options to the specified app for the duration
199
+ # of the block. Unless merge_with_existing is false, the input
200
+ # options will be merged with the existing options; otherwise
201
+ # the app options will be reconfigured to just the inputs.
202
+ #
203
+ # For convenience, with_options is setup such that options
204
+ # {:debug => true, :quiet => true} are implicitly specified.
205
+ # Overrides are respected.
206
+ #
207
+ # app = Tap::App.new(:options => {:one => 1, :two => 2})
208
+ #
209
+ # with_options({:one => 'one', :quiet => false}, app) do
210
+ # app.options.marshal_dump # => {:one => 'one', :two => 2, :debug => true, :quiet => false}
211
+ # end
212
+ #
213
+ # app.options.marshal_dump # => {:one => 1, :two => 2}
214
+ #
215
+ def with_options(options={}, app=self.app, merge_with_existing=true, &block)
216
+ app_config = {:options => options}
217
+ with_config(app_config, app, merge_with_existing, &block)
218
+ end
219
+
220
+ # Applies the input configurations to the specified app for the
221
+ # duration of the block. Unless merge_with_existing is false,
222
+ # the input configurations will be merged with the existing
223
+ # configurations; otherwise the app will be reconfigured to
224
+ # using the inputs as specified.
225
+ #
226
+ # For convenience, with_config is setup such that options
227
+ # {:debug => true, :quiet => true} are implicitly specified.
228
+ # Overrides are respected.
229
+ #
230
+ # app = Tap::App.new(:directories => {:dir => 'dir', :alt => 'alt_dir'})
231
+ # tmp_config = {
232
+ # :directories => {:alt => 'another', :new => 'new_dir'},
233
+ # :options => {:one => 1, :quiet => false}}
234
+ #
235
+ # with_config(tmp_config, app) do
236
+ # app.directories # => {:dir => 'dir', :alt => 'another', :new => 'new_dir'}
237
+ # app.options.marshal_dump # => {:one => 1, :debug => true, :quiet => false}
238
+ # end
239
+ #
240
+ # app.directories # => {:dir => 'dir', :alt => 'alt_dir'}
241
+ # app.options.marshal_dump # => {}
242
+ #
243
+ def with_config(app_config={}, app=self.app, merge_with_existing=true, default_options={:debug => true, :quiet => true}, &block)
244
+ begin
245
+ hold = app.config
246
+
247
+ app_config[:options] = default_options.merge(app_config[:options] || {})
248
+ if merge_with_existing
249
+ hold.each_pair do |key, value|
250
+ next unless app_config.has_key?(key)
251
+ next unless value.kind_of?(Hash)
252
+
253
+ app_config[key] = value.merge(app_config[key])
254
+ end
255
+ end
256
+
257
+ app.reconfigure(app_config)
258
+
259
+ yield block if block_given?
260
+ ensure
261
+ app.reconfigure(hold)
262
+ end
263
+ end
264
+
265
+ end
266
+ end
267
+ end
268
+
269
+
270
+
271
+