bahuvrihi-tap 0.11.2 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/bin/rap +2 -3
  2. data/bin/tap +1 -1
  3. data/cmd/console.rb +2 -2
  4. data/cmd/manifest.rb +2 -2
  5. data/cmd/run.rb +7 -9
  6. data/cmd/server.rb +5 -5
  7. data/doc/Class Reference +17 -20
  8. data/doc/Tutorial +5 -7
  9. data/lib/tap.rb +2 -0
  10. data/lib/tap/app.rb +21 -31
  11. data/lib/tap/constants.rb +2 -2
  12. data/lib/tap/declarations.rb +85 -97
  13. data/lib/tap/declarations/declaration_task.rb +58 -0
  14. data/lib/tap/declarations/description.rb +24 -0
  15. data/lib/tap/env.rb +20 -16
  16. data/lib/tap/exe.rb +2 -2
  17. data/lib/tap/file_task.rb +224 -410
  18. data/lib/tap/generator/arguments.rb +9 -0
  19. data/lib/tap/generator/base.rb +105 -28
  20. data/lib/tap/generator/destroy.rb +29 -12
  21. data/lib/tap/generator/generate.rb +55 -39
  22. data/lib/tap/generator/generators/command/templates/command.erb +3 -3
  23. data/lib/tap/generator/generators/config/config_generator.rb +34 -3
  24. data/lib/tap/generator/generators/root/root_generator.rb +6 -9
  25. data/lib/tap/generator/generators/root/templates/Rakefile +4 -4
  26. data/lib/tap/generator/generators/task/templates/test.erb +1 -1
  27. data/lib/tap/root.rb +211 -156
  28. data/lib/tap/support/aggregator.rb +6 -9
  29. data/lib/tap/support/audit.rb +278 -357
  30. data/lib/tap/support/constant_manifest.rb +24 -21
  31. data/lib/tap/support/dependency.rb +1 -1
  32. data/lib/tap/support/executable.rb +26 -48
  33. data/lib/tap/support/join.rb +44 -19
  34. data/lib/tap/support/joins/sync_merge.rb +3 -5
  35. data/lib/tap/support/parser.rb +1 -1
  36. data/lib/tap/task.rb +195 -150
  37. data/lib/tap/tasks/dump.rb +2 -2
  38. data/lib/tap/test/extensions.rb +11 -13
  39. data/lib/tap/test/file_test.rb +71 -129
  40. data/lib/tap/test/file_test_class.rb +4 -1
  41. data/lib/tap/test/tap_test.rb +26 -154
  42. metadata +15 -22
  43. data/lib/tap/patches/optparse/summarize.rb +0 -62
  44. data/lib/tap/support/assignments.rb +0 -173
  45. data/lib/tap/support/class_configuration.rb +0 -182
  46. data/lib/tap/support/configurable.rb +0 -113
  47. data/lib/tap/support/configurable_class.rb +0 -271
  48. data/lib/tap/support/configuration.rb +0 -170
  49. data/lib/tap/support/instance_configuration.rb +0 -173
  50. data/lib/tap/support/lazydoc.rb +0 -386
  51. data/lib/tap/support/lazydoc/attributes.rb +0 -48
  52. data/lib/tap/support/lazydoc/comment.rb +0 -503
  53. data/lib/tap/support/lazydoc/config.rb +0 -17
  54. data/lib/tap/support/lazydoc/definition.rb +0 -36
  55. data/lib/tap/support/lazydoc/document.rb +0 -152
  56. data/lib/tap/support/lazydoc/method.rb +0 -24
  57. data/lib/tap/support/tdoc.rb +0 -409
  58. data/lib/tap/support/tdoc/tdoc_html_generator.rb +0 -38
  59. data/lib/tap/support/tdoc/tdoc_html_template.rb +0 -42
  60. data/lib/tap/support/validation.rb +0 -479
@@ -41,8 +41,8 @@ module Tap
41
41
  app.aggregator.to_hash.each_pair do |src, _results|
42
42
  next if filter && src.to_s !~ filter
43
43
 
44
- results["#{src} (#{src.object_id})"] = _results.collect {|_audit| _audit._current }
45
- _results.each {|_audit| trails << _audit._to_s }
44
+ results["#{src} (#{src.object_id})"] = _results.collect {|_audit| _audit.value }
45
+ _results.each {|_audit| trails << _audit.dump }
46
46
  end
47
47
 
48
48
  if audit
@@ -16,8 +16,8 @@ module Tap
16
16
  end
17
17
 
18
18
  # Causes a TestCase to act as a file test, by including FileTest and
19
- # instantiating class_test_root (a Tap::Root). The root and directories
20
- # used by class_test_root may be specified as options.
19
+ # instantiating class_test_root (a Tap::Root). The root, relative_paths,
20
+ # and absolute_paths used by class_test_root may be specified as options.
21
21
  #
22
22
  # Note: by default acts_as_file_test determines a root directory
23
23
  # <em>based on the calling file</em>. Be sure to specify the root
@@ -26,15 +26,10 @@ module Tap
26
26
  def acts_as_file_test(options={})
27
27
  include Tap::Test::FileTest
28
28
 
29
- options = {
30
- :root => test_root_dir,
31
- :directories => {
32
- :input => 'input',
33
- :output => 'output',
34
- :expected => 'expected'}
35
- }.merge(options)
36
-
37
- self.class_test_root = Tap::Root.new(options[:root], options[:directories])
29
+ self.class_test_root = Tap::Root.new(
30
+ options[:root] || test_root_dir,
31
+ options[:relative_paths] || {},
32
+ options[:absolute_paths] || {})
38
33
  end
39
34
 
40
35
  # Causes a unit test to act as a tap test -- resulting in the following:
@@ -47,14 +42,17 @@ module Tap
47
42
  # directory manually if you call acts_as_file_test from a file that
48
43
  # isn't the test file.
49
44
  def acts_as_tap_test(options={})
45
+ options[:root] ||= test_root_dir
46
+
50
47
  acts_as_subset_test
51
- acts_as_file_test({:root => test_root_dir}.merge(options))
48
+ acts_as_file_test(options)
52
49
 
53
50
  include Tap::Test::TapTest
54
51
  end
55
52
 
56
53
  def acts_as_script_test(options={})
57
- acts_as_file_test({:root => test_root_dir}.merge(options))
54
+ options[:root] ||= test_root_dir
55
+ acts_as_file_test(options)
58
56
 
59
57
  include Tap::Test::ScriptTest
60
58
  end
@@ -7,7 +7,7 @@ module Tap
7
7
  module Test
8
8
 
9
9
  # FileTest facilitates access and utilization of test-specific files and
10
- # directories. FileTest provides each test method is setup with a Tap::Root
10
+ # directories. FileTest provides each test method with a Tap::Root
11
11
  # (method_root) specific for the method, and defines a new assertion method
12
12
  # (assert_files) to facilitate tests which involve the production and/or
13
13
  # modification of files.
@@ -25,32 +25,25 @@ module Tap
25
25
  # method_root.root # => File.join(ctr.root, "/test_something")
26
26
  # method_root[:input] # => File.join(ctr.root, "/test_something/input")
27
27
  #
28
- # # files in the output directory are cleared before
29
- # # and after each test; this passes each time the
28
+ # # files in the :output and :tmp directories are cleared
29
+ # # before and after each test; this passes each time the
30
30
  # # test is run with no additional cleanup:
31
31
  #
32
- # output_file = method_root.filepath(:output, 'sample.txt')
33
- # assert !File.exists?(output_file)
32
+ # assert !File.exists?(method_root[:tmp])
34
33
  #
35
- # make_test_directories # makes the input, output, expected directories
36
- # FileUtils.touch(output_file)
37
- #
38
- # assert File.exists?(output_file)
34
+ # tmp_file = method_root.prepare(:tmp, 'sample.txt') {|file| file << "content" }
35
+ # assert_equal "content", File.read(tmp_file)
39
36
  #
40
37
  # # the assert_files method compares files produced
41
38
  # # by the block the expected files, ensuring they
42
39
  # # are the same (see the documentation for the
43
40
  # # simplest use of assert_files)
44
41
  #
45
- # expected_file = method_root.filepath(:expected, 'output.txt')
46
- # File.open(expected_file, 'w') {|file| file << 'expected output' }
42
+ # expected_file = method_root.prepare(:expected, 'output.txt') {|file| file << 'expected output' }
47
43
  #
48
44
  # # passes
49
45
  # assert_files do
50
- # output_file = method_root.filepath(:output, 'output.txt')
51
- # File.open(output_file, 'w') {|file| file << 'expected output' }
52
- #
53
- # output_file
46
+ # method_root.prepare(:output, 'output.txt') {|file| file << 'expected output' }
54
47
  # end
55
48
  # end
56
49
  # end
@@ -61,67 +54,51 @@ module Tap
61
54
  include Tap::Test::EnvVars
62
55
  include Tap::Test::Assertions
63
56
 
64
- def self.included(base)
57
+ def self.included(base) # :nodoc:
65
58
  super
66
59
  base.extend FileTestClass
60
+ base.cleanup_dirs = [:output, :tmp]
67
61
  end
68
62
 
69
63
  # Convenience method to access the class_test_root.
70
64
  def ctr
71
65
  self.class.class_test_root
72
66
  end
73
-
74
- # Creates the method_root.directories.
75
- def make_test_directories
76
- method_root.directories.values.each do |dir|
77
- FileUtils.mkdir_p( method_root[dir] )
78
- end
79
- end
80
-
81
- # Attempts to remove the method_root.directories, method_root.root,
82
- # and ctr.root. Any given directory will not be removed unless empty.
83
- def cleanup_test_directories
84
- method_root.directories.values.each do |dir|
85
- Utils.try_remove_dir(method_root[dir])
86
- end
87
-
88
- Utils.try_remove_dir(method_root.root)
89
- Utils.try_remove_dir(ctr.root)
90
- end
91
67
 
92
68
  # The test-method-specific Tap::Root which may be used to
93
69
  # access test files. method_root is a duplicate of ctr
94
- # reconfigured so that method_root.root is ctr[ method_name.to_sym ]
70
+ # reconfigured so that method_root.root is ctr[method_name.to_sym]
95
71
  attr_reader :method_root
96
72
 
97
- # An array of filepaths setup by method_tempfile; these files
98
- # are removed by teardown, as they should all be in the output
99
- # directory.
100
- attr_reader :method_tempfiles
101
-
102
- # Sets up method_root and attempts to cleanup any left overs from a
103
- # previous test (ie by deleting method_root[:output] and calling
104
- # cleanup_test_directories). Be sure to call super when overriding
105
- # this method.
73
+ # Sets up method_root and calls cleanup. Be sure to call super when
74
+ # overriding this method.
106
75
  def setup
107
76
  super
108
77
  @method_root = ctr.dup.reconfigure(:root => ctr[method_name.to_sym])
109
- @method_tempfiles = []
110
-
111
- Utils.clear_dir(method_root[:output])
112
- cleanup_test_directories
78
+ cleanup
79
+ end
80
+
81
+ # Cleans up the method_root.root directory by removing the class
82
+ # cleanup_dirs (by default :tmp and :output). The root directory
83
+ # will also be removed if it is empty.
84
+ #
85
+ # Override as necessary in subclasses.
86
+ def cleanup
87
+ self.class.cleanup_dirs.each do |dir|
88
+ Utils.clear_dir(method_root[dir])
89
+ end
90
+ Utils.try_remove_dir(method_root.root)
113
91
  end
114
92
 
115
- # Deletes the the method_root[:output] directory (unless flagged
116
- # otherwise by an ENV variable) and calls cleanup_test_directories.
117
- # To keep all output directories, or to only keep output directories
118
- # for failing tests, set the 'KEEP_OUTPUTS' or 'KEEP_FAILURES' ENV
119
- # variables:
93
+ # Calls cleanup unless flagged otherwise by an ENV variable. To prevent
94
+ # cleanup (when debugging for example), set the 'KEEP_OUTPUTS' or
95
+ # 'KEEP_FAILURES' ENV variables:
120
96
  #
121
97
  # % rap test KEEP_OUTPUTS=true
122
98
  # % rap test KEEP_FAILURES=true
123
99
  #
124
- # Be sure to call super when overriding this method.
100
+ # Cleanup is only suppressed for failing tests when KEEP_FAILURES is
101
+ # specified. Be sure to call super when overriding this method.
125
102
  def teardown
126
103
  # check that method_root still exists (nil may
127
104
  # indicate setup was overridden without super)
@@ -132,65 +109,34 @@ module Tap
132
109
  # clear out the output folder if it exists, unless flagged otherwise
133
110
  unless env("KEEP_OUTPUTS") || (!passed? && env("KEEP_FAILURES"))
134
111
  begin
135
- Utils.clear_dir(method_root[:output])
112
+ cleanup
136
113
  rescue
137
- raise("teardown failure: could not remove output files (#{$!.message})")
114
+ raise("cleanup failure: #{$!.message}")
138
115
  end
139
116
  end
140
117
 
141
- cleanup_test_directories
118
+ Utils.try_remove_dir(ctr.root)
142
119
  end
143
120
 
144
121
  # Returns method_name as a string (Ruby 1.9 symbolizes method_name)
145
122
  def method_name_str
146
123
  method_name.to_s
147
124
  end
148
-
149
- # Generates a temporary filepath formatted like "output_dir\filename.n.ext"
150
- # where n is a counter that ensures the filepath is unique and non-existant
151
- # (specificaly n is equal to the number of method_tempfiles generated
152
- # by the current test, incremented as necessary to achieve a non-existant
153
- # filepath).
154
- #
155
- # Unlike Tempfile, method_tempfile does not create the filepath unless a
156
- # block is given, in which case an open File will be passed to the block.
157
- # In addition, method_tempfiles are only cleaned up indirectly when the
158
- # output directory is removed by teardown; this is both convenient for
159
- # testing (when you may want a the file to persist, so you can debug it)
160
- # and less enforcing than Tempfile.
161
- #
162
- # Notes:
163
- # - by default filename is the calling method
164
- # - the extension is chomped off the end of the filename
165
- # - the directory for the file will be created if it does not exist
166
- # - like all files in the output directory, tempfiles will be deleted by
167
- # the default +teardown+ method
168
- def method_tempfile(filename=method_name_str, &block)
169
- ext = File.extname(filename)
170
- basename = filename.chomp(ext)
171
- path = next_indexed_path(method_root.filepath(:output, basename), method_tempfiles.length, ext)
172
- dirname = File.dirname(path)
173
-
174
- method_tempfiles << path
175
- FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
176
- File.open(path, "w", &block) if block_given?
177
- path
178
- end
179
125
 
180
- # assert_files runs a file-based test that feeds all files from input_dir
181
- # to the block, then compares the resulting files (which should be relative to
182
- # output_dir) with all the files in expected_dir. Only the files returned by
183
- # the block are used in the comparison; additional files in the output directory
184
- # are effectively ignored.
126
+ # Runs a file-based test that compares files created by the block with
127
+ # files in an expected directory. The block receives files from the
128
+ # input directory, and should return a list of files relative to the
129
+ # output directory. Only the files returned by the block are compared;
130
+ # additional files in the output directory are effectively ignored.
185
131
  #
186
132
  # === Example
187
- # Lets define a test that transforms input files into output files in a trivial
188
- # way, simply by replacing 'input' with 'output' in the file.
133
+ # Lets define a test that transforms input files into output files in a
134
+ # trivial way, simply by replacing 'input' with 'output' in the file.
189
135
  #
190
136
  # class FileTestDocTest < Test::Unit::TestCase
191
137
  # acts_as_file_test
192
138
  #
193
- # def test_sub
139
+ # def test_assert_files
194
140
  # assert_files do |input_files|
195
141
  # input_files.collect do |filepath|
196
142
  # input = File.read(filepath)
@@ -206,9 +152,9 @@ module Tap
206
152
  # end
207
153
  # end
208
154
  #
209
- # Now say you had some input and expected files for the 'test_sub' method:
155
+ # Now say you had some input and expected files for test_assert_files:
210
156
  #
211
- # file_test_doc/test_sub
157
+ # file_test_doc/test_assert_files
212
158
  # |- expected
213
159
  # | |- one.txt
214
160
  # | `- two.txt
@@ -229,20 +175,21 @@ module Tap
229
175
  # test output 2
230
176
  #
231
177
  # When you run the test, the assert_files passes the input files to the
232
- # block. When the block completes, assert_files compares the output files
233
- # returned by the block with the files in the expected directory. In this
234
- # case, the files are equal and the test passes.
178
+ # block. When the block completes, assert_files compares the output
179
+ # files returned by the block with the files in the expected directory.
180
+ # In this case, the files are equal and the test passes.
235
181
  #
236
182
  # Say you changed the content of one of the expected files:
237
183
  #
238
184
  # [expected/one.txt]
239
185
  # test flunk 1
240
186
  #
241
- # Now the test fails because the output files aren't equal to the expected
242
- # files. The test will also fail if there are missing or extra files.
187
+ # Now the test fails because the output files aren't equal to the
188
+ # expected files. The test also fails if there are missing or extra
189
+ # files.
243
190
  #
244
191
  # === Options
245
- # A variety of options can be specified to adjust the behavior of assert_files:
192
+ # A variety of options adjust the behavior of assert_files:
246
193
  #
247
194
  # :input_dir specify the directory to glob for input files
248
195
  # (default method_root[:input])
@@ -258,15 +205,17 @@ module Tap
258
205
  # expected-output file list comparison
259
206
  # (by default dirs are excluded)
260
207
  #
261
- # assert_files will fail if <tt>:expected_files</tt> was not specified in the
262
- # options and no files were found in <tt>:expected_dir</tt>. This check tries
263
- # to prevent silent false-positive results when you forget to put expected files
264
- # in their place.
208
+ # assert_files will fail if <tt>:expected_files</tt> was not specified
209
+ # in the options and no files were found in <tt>:expected_dir</tt>. This
210
+ # check tries to prevent silent false-positive results when you forget to
211
+ # put expected files in their place.
265
212
  #
266
213
  # === File References
267
- # Sometimes the same files will get used across multiple tests. To allow separate
268
- # management of test files and prevent duplication, file references can be provided
269
- # in place of test files. For instance, with a test directory like:
214
+ #
215
+ # Sometimes the same files will get used across multiple tests. To allow
216
+ # separate management of test files and prevent duplication, file
217
+ # references can be provided in place of test files. For instance, with a
218
+ # test directory like:
270
219
  #
271
220
  # method_root
272
221
  # |- expected
@@ -279,8 +228,8 @@ module Tap
279
228
  # |- one.txt
280
229
  # `- two.txt
281
230
  #
282
- # The input and expected files (all references in this case) can be dereferenced
283
- # to the 'ref' filepaths like so:
231
+ # The input and expected files (all references in this case) can be
232
+ # dereferenced to the 'ref' filepaths like so:
284
233
  #
285
234
  # assert_files :reference_dir => method_root[:ref] do |input_files|
286
235
  # input_files # => ['method_root/ref/one.txt', 'method_root/ref/two.txt']
@@ -292,16 +241,17 @@ module Tap
292
241
  # end
293
242
  # end
294
243
  #
295
- # Dereferencing occurs relative to the input_dir/expected_dir configurations; a
296
- # reference_dir must be specified for dereferencing to occur (see Utils.dereference
297
- # for more details).
244
+ # Dereferencing occurs relative to the input_dir/expected_dir
245
+ # configurations; a reference_dir must be specified for dereferencing to
246
+ # occur (see Utils.dereference for more details).
298
247
  #
299
248
  # === Keeping Outputs
300
- # By default FileTest sets teardown to cleans up the output directory. For
301
- # ease in debugging, ENV variable flags can be specified to keep all output
302
- # files (KEEP_OUTPUTS) or to keep the output files for just the tests that fail
303
- # (KEEP_FAILURES). These flags can be specified from the command line if you're
304
- # running the tests with rake or rap:
249
+ #
250
+ # By default FileTest cleans up everything under method_root except the
251
+ # input and expected directories. For ease in debugging, ENV variable
252
+ # flags can be specified to prevent cleanup for all tests (KEEP_OUTPUTS)
253
+ # or just tests that fail (KEEP_FAILURES). These flags can be specified
254
+ # from the command line if you're running the tests with rake or rap:
305
255
  #
306
256
  # % rake test keep_outputs=true
307
257
  # % rap test keep_failures=true
@@ -346,8 +296,6 @@ module Tap
346
296
  private
347
297
 
348
298
  def transform_test(block, options={}) # :yields: expected_files, output_files
349
- make_test_directories
350
-
351
299
  options = default_assert_files_options.merge(options)
352
300
  input_dir = options[:input_dir]
353
301
  output_dir = options[:output_dir]
@@ -409,12 +357,6 @@ module Tap
409
357
  end
410
358
  end
411
359
 
412
- # utility method for method_tempfile; increments index until the
413
- # path base.indexext does not exist.
414
- def next_indexed_path(base, index, ext) # :nodoc:
415
- path = sprintf('%s.%d%s', base, index, ext)
416
- File.exists?(path) ? next_indexed_path(base, index + 1, ext) : path
417
- end
418
360
  end
419
361
  end
420
362
  end
@@ -4,9 +4,12 @@ module Tap
4
4
  # Class methods extending tests which include FileTest.
5
5
  module FileTestClass
6
6
 
7
- # The class-level test root (a Tap::Root).
7
+ # The class-level test root (a Tap::Root)
8
8
  attr_accessor :class_test_root
9
9
 
10
+ # An array of directories to be cleaned up by cleanup
11
+ attr_accessor :cleanup_dirs
12
+
10
13
  end
11
14
  end
12
15
  end
@@ -1,32 +1,6 @@
1
1
  module Tap
2
2
  module Test
3
3
 
4
- # Used during check_audit to hold the sources and values of an audit
5
- # in the correct order. Oriented so that the next value to be checked
6
- # is at the top of the stack. Used internally.
7
- class AuditStack # :nodoc:
8
- attr_reader :test
9
-
10
- def initialize(test)
11
- @test = test
12
- @stack = []
13
- end
14
-
15
- def load_audit(values)
16
- [values._sources, values._values].transpose.reverse_each do |sv|
17
- load(*sv)
18
- end
19
- end
20
-
21
- def load(source, value)
22
- @stack.unshift [source, value]
23
- end
24
-
25
- def next
26
- @stack.shift
27
- end
28
- end
29
-
30
4
  # Tap-specific testing methods to help with testing Tasks, such as the
31
5
  # checking of audits and test-specific modification of application
32
6
  # configuration.
@@ -40,7 +14,7 @@ module Tap
40
14
  attr_reader :app
41
15
 
42
16
  # Setup creates a test-method-specific application that is initialized
43
- # to the method_root, and uses the directories and absolute paths from
17
+ # to the method_root, and uses the relative and absolute paths from
44
18
  # trs (the test root structure, see Tap::Test::FileTest).
45
19
  #
46
20
  # Also makes sure Tap::App.instance returns the test method app.
@@ -50,153 +24,51 @@ module Tap
50
24
  Tap::App.instance = @app
51
25
  end
52
26
 
53
- #
54
- # audit test methods
55
- #
56
-
57
- # Used to define expected audits in Tap::Test::TapTest#assert_audit_equal
58
- class ExpAudit < Array
59
- end
60
-
61
- # Used to define merged audit trails in Tap::Test::TapTest#assert_audit_equal
62
- class ExpMerge < Array
63
- end
64
-
65
- class Tracer
66
- include Tap::Support::Executable
67
-
68
- class << self
69
- def intern(n, app, runlist)
70
- Array.new(n) { |index| new(index, app, runlist) }
71
- end
72
- end
73
-
74
- def initialize(index, app, runlist)
75
- @index = index
76
- @runlist = runlist
77
-
78
- @app = app
79
- @_method_name = :trace
80
- @on_complete_block =nil
81
- @dependencies = []
82
- @batch = [self]
83
- end
84
-
85
- def concat(str, id)
86
- "#{str} #{id}".strip
87
- end
88
-
89
- def trace(trace)
90
- id = "#{@index}.#{batch_index}"
91
- @runlist << id
92
-
93
- case trace
94
- when Array then trace.collect {|str| concat(str, id) }
95
- when String then concat(trace, id)
96
- else raise "cannot utilize trace: #{trace}"
97
- end
98
- end
99
- end
100
-
101
27
  # Asserts that an array of audits are all equal, basically feeding
102
28
  # each pair of audits to assert_audit_equal.
103
- def assert_audits_equal(expected, audits)
104
- error_msg = "expected <#{audits.length}> audits, but was <#{expected.length}>"
105
- Utils.each_pair_with_index(expected, audits, error_msg) do |exp, audit, index|
106
- assert_audit_equal(exp, audit, [index])
29
+ def assert_audits_equal(expected, audits, msg=nil, &block)
30
+ assert_equal expected.length, audits.length, "expected <#{expected.length}> audits, but was <#{audits.length}>"
31
+ Utils.each_pair_with_index(expected, audits) do |exp, audit, index|
32
+ assert_audit_equal(exp, audit, &block)
107
33
  end
108
34
  end
109
35
 
110
- # Asserts that an audit is as expected. The expected audit should
111
- # be an ExpAudit (just a subclass of Array) that records the sources
112
- # and the values at each step in the audit trail. Proc objects can
113
- # be provided in place of expected records that are hard or impossible
114
- # to provide directly; the Proc will be used to validate the actual
115
- # record. Merges must be marked in the ExpAudit using ExpMerge.
36
+ # Asserts that an audit trail matches the expected trail. By default
37
+ # the expected trail should be composed of [key, value] arrays
38
+ # representing each audit, but a block may be provided to collect other
39
+ # attributes.
116
40
  #
117
41
  # Simple assertion:
118
42
  #
119
- # a = Tap::Support::Audit.new
120
- # a._record(:a, 'a')
121
- # a._record(:b, 'b')
122
- #
123
- # e = ExpAudit[[:a, 'a'], [:b, 'b']]
124
- # assert_audit_equal(e, a)
125
- #
126
- # Assertion validating a record with a Proc (any number of
127
- # records can be validated with a Proc):
128
- #
129
- # a = Tap::Support::Audit.new
130
- # a._record(:a, 'a')
131
- # a._record(:b, 'b')
43
+ # a = Audit.new(:a, 'a')
44
+ # b = Audit.new(:b, 'b', a)
132
45
  #
133
- # e = ExpAudit[
134
- # lambda {|source, value| source == :a && value == 'a'},
135
- # [:b, 'b']]
136
- # assert_audit_equal(e, a)
46
+ # e = [[:a, 'a'], [:b, 'b']]
47
+ # assert_audit_equal(e, b)
137
48
  #
138
49
  # Assertion with merge:
139
50
  #
140
- # a = Tap::Support::Audit.new
141
- # a._record(:a, 'a')
142
- # a._record(:b, 'b')
51
+ # a = Audit.new(:a, 'a')
52
+ # b = Audit.new(:b, 'b', a)
143
53
  #
144
- # b = Tap::Support::Audit.new
145
- # b._record(:c, 'c')
146
- # b._record(:d, 'd')
54
+ # c = Audit.new(:c, 'c')
55
+ # d = Audit.new(:d, 'd', c)
147
56
  #
148
- # c = Tap::Support::Audit.merge(a,b)
149
- # c._record(:e, 'e')
150
- # c._record(:f, 'f')
57
+ # e = Audit.new(:e, 'e')
58
+ # f = Audit.new(:f, 'f', [b,d])
151
59
  #
152
- # ea = ExpAudit[[:a, "a"], [:b, "b"]]
153
- # eb = ExpAudit[[:c, "c"], [:d, "d"]]
154
- # e = ExpAudit[ExpMerge[ea, eb], [:e, "e"], [:f, "f"]]
60
+ # eb = [[:a, "a"], [:b, "b"]]
61
+ # ed = [[:c, "c"], [:d, "d"]]
62
+ # e = [[eb, ed], [:e, "e"], [:f, "f"]]
155
63
  #
156
64
  # assert_audit_equal(e, c)
157
65
  #
158
- # When assert_audit_equal fails, a string of indicies is provided
159
- # to help locate which record was unequal. For instance in the last
160
- # example, say we used:
161
- #
162
- # ea = ExpAudit[[:a, "a"], [:b, "FLUNK"]]
163
- # eb = ExpAudit[[:c, "c"], [:d, "d"]]
164
- # e = ExpAudit[ExpMerge[ea, eb], [:e, "e"], [:f, "f"]]
165
- #
166
- # The failure message will read something like 'unequal record 0:0:1'
167
- # indicating it was e[0][0][1] that failed. Working through it,
168
- # remembering that ExpAudit and ExpMerge are just subclasses of
169
- # Array:
170
- #
171
- # e # => ExpAudit[ExpMerge[ea, eb], [:e, "e"], [:f, "f"]]
172
- # e[0] # => ExpMerge[ea, eb]
173
- # e[0][0] # => ExpAudit[[:a, "a"], [:b, "FLUNK"]]
174
- # e[0][0][1] # => [:b, "FLUNK"]
175
- #
176
- def assert_audit_equal(expected, audit, nesting=[])
177
- actual = audit._collect_records {|source, value| [source, value]}
178
- assert_audit_records_equal(expected, actual, nesting)
66
+ def assert_audit_equal(expected, audit, msg=nil, &block)
67
+ block = lambda {|audit| [audit.key, audit.value] } unless block
68
+ actual = audit.trail(&block)
69
+ assert_equal(expected, actual, msg)
179
70
  end
180
71
 
181
- def assert_audit_records_equal(expected, actual, nesting=[])
182
- assert_equal ExpAudit, expected.class
183
- assert_equal expected.length, actual.length, "unequal number of records"
184
-
185
- expected.each_with_index do |exp_record, i|
186
- case exp_record
187
- when ExpMerge
188
- flunk "empty merge #{(nesting + [i]).join(':')}" if exp_record.empty?
189
- exp_record.each_with_index do |exp_audit, j|
190
- assert_audit_records_equal(exp_audit, actual[i][j], nesting + [i,j])
191
- end
192
- when Proc
193
- assert exp_record.call(*actual[i]), "unconfirmed record #{(nesting + [i]).join(':')}"
194
- else
195
- assert_equal exp_record, actual[i], "unequal record #{(nesting + [i]).join(':')}"
196
- end
197
- end
198
- end
199
-
200
72
  # The configurations used to initialize self.app
201
73
  def app_config
202
74
  method_root.config.to_hash.merge(:quiet => true, :debug => true)