bahuvrihi-tap 0.10.4 → 0.10.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/bin/rap +112 -0
  2. data/bin/tap +21 -10
  3. data/cmd/destroy.rb +1 -1
  4. data/cmd/generate.rb +1 -1
  5. data/cmd/run.rb +4 -48
  6. data/cmd/server.rb +3 -1
  7. data/lib/tap/constants.rb +1 -1
  8. data/lib/tap/env.rb +37 -39
  9. data/lib/tap/exe.rb +59 -29
  10. data/lib/tap/generator/base.rb +1 -1
  11. data/lib/tap/generator/generators/config/templates/doc.erb +1 -1
  12. data/lib/tap/generator/generators/file_task/templates/test.erb +1 -1
  13. data/lib/tap/generator/generators/root/templates/README +0 -0
  14. data/lib/tap/generator/generators/root/templates/gemspec +3 -4
  15. data/lib/tap/generator/generators/root/templates/tapfile +3 -3
  16. data/lib/tap/parser.rb +35 -0
  17. data/lib/tap/patches/optparse/summarize.rb +62 -0
  18. data/lib/tap/root.rb +24 -18
  19. data/lib/tap/support/class_configuration.rb +1 -1
  20. data/lib/tap/support/configurable_class.rb +3 -1
  21. data/lib/tap/support/configuration.rb +19 -0
  22. data/lib/tap/support/constant.rb +14 -2
  23. data/lib/tap/support/declarations.rb +33 -39
  24. data/lib/tap/support/dependable.rb +21 -2
  25. data/lib/tap/support/gems.rb +4 -30
  26. data/lib/tap/support/gems/rack.rb +14 -11
  27. data/lib/tap/support/lazy_attributes.rb +1 -1
  28. data/lib/tap/support/lazydoc.rb +257 -340
  29. data/lib/tap/support/lazydoc/comment.rb +499 -0
  30. data/lib/tap/support/lazydoc/config.rb +17 -0
  31. data/lib/tap/support/lazydoc/declaration.rb +20 -0
  32. data/lib/tap/support/lazydoc/document.rb +118 -0
  33. data/lib/tap/support/lazydoc/method.rb +24 -0
  34. data/lib/tap/support/manifest.rb +33 -4
  35. data/lib/tap/support/validation.rb +56 -0
  36. data/lib/tap/task.rb +46 -44
  37. data/lib/tap/tasks/dump.rb +15 -10
  38. data/lib/tap/tasks/load.rb +25 -0
  39. data/lib/tap/tasks/rake.rb +2 -2
  40. data/lib/tap/test.rb +55 -36
  41. data/lib/tap/test/file_methods.rb +204 -178
  42. data/lib/tap/test/file_methods_class.rb +4 -18
  43. data/lib/tap/test/script_methods.rb +76 -90
  44. data/lib/tap/test/script_methods/regexp_escape.rb +92 -0
  45. data/lib/tap/test/script_methods/script_test.rb +4 -2
  46. data/lib/tap/test/subset_methods.rb +46 -49
  47. data/lib/tap/test/subset_methods_class.rb +17 -54
  48. data/lib/tap/test/tap_methods.rb +1 -5
  49. data/lib/tap/test/utils.rb +142 -32
  50. metadata +12 -3
  51. data/lib/tap/support/command_line.rb +0 -55
  52. data/lib/tap/support/comment.rb +0 -270
@@ -2,21 +2,26 @@ module Tap
2
2
  module Tasks
3
3
  # :startdoc::manifest the default dump task
4
4
  #
5
- # A dump task to print application results to a file or IO. The results are
6
- # printed in a format allowing dumped results to be reloaded and used as
7
- # inputs to other tasks. See Tap::Load for more details.
5
+ # A dump task to print aggregated application results to a file or IO.
6
+ # The results are printed as YAML, allowing dumped results to be
7
+ # reloaded and used as inputs to other tasks.
8
8
  #
9
- # Often dump is used as the final task in a round of tasks; if no filepath is
10
- # specified, the results are printed to stdout.
9
+ # Often dump is used as the final task in a round of tasks; if no filepath
10
+ # is specified, the results are printed to stdout.
11
11
  #
12
- # % tap run -- [your tasks] --+ dump FILEPATH
12
+ # % tap run -- [tasks] --+ dump FILEPATH
13
13
  #
14
+ # See Tap::Load for more details.
14
15
  class Dump < Tap::FileTask
15
16
 
16
17
  config :date_format, '%Y-%m-%d %H:%M:%S' # the date format
17
18
  config :audit, true, &c.switch # include the audit trails
18
19
  config :date, true, &c.switch # include a date
19
-
20
+ config :filter, nil, &c.regexp_or_nil # only dump matching objects
21
+
22
+ # Calls dump_to with the target. If the target is not an
23
+ # IO, process assumes the target is a filepath. In that
24
+ # case, the file is prepared and the results dumped to it.
20
25
  def process(target=$stdout)
21
26
  case target
22
27
  when IO then dump_to(target)
@@ -34,9 +39,9 @@ module Tap
34
39
  trails = []
35
40
  results = {}
36
41
  app.aggregator.to_hash.each_pair do |src, _results|
37
- name = src.respond_to?(:name) ? src.name : ''
38
-
39
- results["#{name} (#{src.object_id})"] = _results.collect {|_audit| _audit._current }
42
+ next if filter && src.to_s !~ filter
43
+
44
+ results["#{src} (#{src.object_id})"] = _results.collect {|_audit| _audit._current }
40
45
  _results.each {|_audit| trails << _audit._to_s }
41
46
  end
42
47
 
@@ -0,0 +1,25 @@
1
+ module Tap
2
+ module Tasks
3
+ # :startdoc::manifest the default load task
4
+ #
5
+ # Load YAML-formatted data, as may be produced using Tap::Dump,
6
+ # and makes this data available for other tasks. Load is often
7
+ # used as a gateway task to other tasks.
8
+ #
9
+ # % tap run -- load FILEPATH --: [task]
10
+ #
11
+ class Load < Tap::Task
12
+
13
+ def process(input)
14
+ obj = case input
15
+ when StringIO then YAML.load(input.read)
16
+ else
17
+ log :load, input
18
+ YAML.load_file(input)
19
+ end
20
+
21
+ obj.values.flatten
22
+ end
23
+ end
24
+ end
25
+ end
@@ -45,9 +45,9 @@ module Tap
45
45
 
46
46
  class << self
47
47
 
48
- # Overrides Tap::Support::FrameworkClass#instantiate to do
48
+ # Overrides Tap::Support::FrameworkClass#parse! to do
49
49
  # nothing so that all args get passed forward to rake.
50
- def instantiate(argv, app=Tap::App.instance) # => instance, argv
50
+ def parse!(argv, app=Tap::App.instance) # => instance, argv
51
51
  if argv.include?('--help')
52
52
  puts help
53
53
  exit
data/lib/tap/test.rb CHANGED
@@ -1,21 +1,14 @@
1
1
  require 'test/unit'
2
+ $:.unshift File.expand_path("#{File.dirname(__FILE__)}/..")
2
3
 
3
4
  module Test # :nodoc:
4
5
  module Unit # :nodoc:
5
6
 
6
- # Methods extending TestCase.
7
- #
8
- # === Method Availability
9
- # Note that these methods are added piecemeal by Tap::Test::SubsetMethods,
10
- # Tap::Test::FileMethods and Tap::Test::TapMethods, but that fact doesn't
11
- # come through in the documentation. Hence, not all of them will be available
12
- # if you're only using SubsetMethods or FileMethods. Breaks down like this:
13
- #
14
- # Using: Methods Available:
15
- # TapMethods all
16
- # FileMethods all, except acts_as_tap_test
17
- # SubsetMethods all, except acts_as_tap_test, acts_as_file_test, file_test_root
18
- #
7
+ # Methods extending TestCase. For more information see:
8
+ # - Tap::Test::SubsetMethods
9
+ # - Tap::Test::FileMethods
10
+ # - Tap::Test::TapMethods
11
+ #
19
12
  #--
20
13
  #See the TestTutorial for more information.
21
14
  class TestCase
@@ -26,11 +19,12 @@ module Test # :nodoc:
26
19
  child.instance_variable_set(:@run_test_suite, true)
27
20
  end
28
21
 
29
- #
30
- # Methods for skipping a test suite
31
- #
32
-
22
+ # Indicates when the test suite should be run or skipped.
33
23
  attr_accessor :run_test_suite
24
+
25
+ # An array of messages printed when a test is skipped
26
+ # by setting run_test_suite to false.
27
+ attr_reader :skip_messages
34
28
 
35
29
  # Causes a test suite to be skipped. If a message is given, it will
36
30
  # print and notify the user the test suite has been skipped.
@@ -39,39 +33,46 @@ module Test # :nodoc:
39
33
 
40
34
  # experimental -- perhaps use this so that a test can be skipped
41
35
  # for multiple reasons?
42
- @skip_messages << msg
36
+ skip_messages << msg
43
37
  end
44
38
 
45
39
  alias :original_suite :suite
46
40
 
47
- # Modifies the default suite method to include/exclude tests based on platform.
41
+ # Modifies the default suite method to skip the suit unless
42
+ # run_test_suite is true. If the test is skipped, the skip_messages
43
+ # will be printed along with the default 'Skipping <Test>' message.
48
44
  def suite # :nodoc:
49
45
  if run_test_suite
50
46
  original_suite
51
47
  else
52
- skip_message = @skip_messages.compact.join(', ')
48
+ skip_message = skip_messages.compact.join(', ')
53
49
  puts "Skipping #{name}#{skip_message.empty? ? '' : ': ' + skip_message}"
50
+
51
+ # return an empty test suite of the appropriate name
54
52
  Test::Unit::TestSuite.new(name)
55
53
  end
56
54
  end
57
55
 
58
- # Causes a TestCase to act as a file test, by instantiating a class Tap::Root
59
- # (trs), and including FileMethods. The root and directories used to
60
- # instantiate trs can be specified as options. By default file_test_root
61
- # and the directories {:input => 'input', :output => 'output', :expected => 'expected'}
62
- # will be used.
56
+ # Causes a TestCase to act as a file test, by including FileMethods and
57
+ # instantiating class_test_root (a Tap::Root). The root and directories
58
+ # used by class_test_root may be specified as options.
63
59
  #
64
- # Note: file_test_root determines a root directory <em>based on the calling file</em>.
65
- # Be sure to specify the root directory explicitly if you call acts_as_file_test
66
- # from a file that is NOT meant to be test file.
60
+ # Note: by default acts_as_file_test determines a root directory
61
+ # <em>based on the calling file</em>. Be sure to specify the root
62
+ # directory manually if you call acts_as_file_test from a file that
63
+ # isn't the test file.
67
64
  def acts_as_file_test(options={})
68
65
  include Tap::Test::FileMethods
69
66
 
70
67
  options = {
71
- :root => file_test_root,
72
- :directories => {:input => 'input', :output => 'output', :expected => 'expected'}
68
+ :root => test_root_dir,
69
+ :directories => {
70
+ :input => 'input',
71
+ :output => 'output',
72
+ :expected => 'expected'}
73
73
  }.merge(options)
74
- self.trs = Tap::Root.new(options[:root], options[:directories])
74
+
75
+ self.class_test_root = Tap::Root.new(options[:root], options[:directories])
75
76
  end
76
77
 
77
78
  # Causes a unit test to act as a tap test -- resulting in the following:
@@ -79,23 +80,39 @@ module Test # :nodoc:
79
80
  # - inclusion of Tap::Test::SubsetMethods
80
81
  # - inclusion of Tap::Test::InstanceMethods
81
82
  #
82
- # Note: Unless otherwise specified, <tt>acts_as_tap_test</tt> infers a root directory
83
- # based on the calling file. Be sure to specify the root directory explicitly
84
- # if you call acts_as_file_test from a file that is NOT meant to be test file.
83
+ # Note: by default acts_as_tap_test determines a root directory
84
+ # <em>based on the calling file</em>. Be sure to specify the root
85
+ # directory manually if you call acts_as_file_test from a file that
86
+ # isn't the test file.
85
87
  def acts_as_tap_test(options={})
86
88
  include Tap::Test::SubsetMethods
87
89
  include Tap::Test::FileMethods
88
90
  include Tap::Test::TapMethods
89
91
 
90
- acts_as_file_test({:root => file_test_root}.merge(options))
92
+ acts_as_file_test({:root => test_root_dir}.merge(options))
91
93
  end
92
94
 
93
95
  def acts_as_script_test(options={})
94
96
  include Tap::Test::FileMethods
95
97
  include Tap::Test::ScriptMethods
96
98
 
97
- acts_as_file_test({:root => file_test_root}.merge(options))
99
+ acts_as_file_test({:root => test_root_dir}.merge(options))
100
+ end
101
+
102
+ private
103
+
104
+ # Infers the test root directory from the calling file.
105
+ # 'some_class.rb' => 'some_class'
106
+ # 'some_class_test.rb' => 'some_class'
107
+ def test_root_dir # :nodoc:
108
+ # caller[1] is considered the calling file (which should be the test case)
109
+ # note that the output of calller.first is like:
110
+ # ./path/to/file.rb:10
111
+ # ./path/to/file.rb:10:in 'method'
112
+ calling_file = caller[1].gsub(/:\d+(:in .*)?$/, "")
113
+ calling_file.chomp(File.extname(calling_file)).chomp("_test")
98
114
  end
115
+
99
116
  end
100
117
  end
101
118
  end
@@ -110,6 +127,8 @@ module Tap
110
127
  autoload(:SubsetMethods, 'tap/test/subset_methods')
111
128
  autoload(:FileMethods, 'tap/test/file_methods')
112
129
  autoload(:TapMethods, 'tap/test/tap_methods')
130
+ autoload(:ScriptMethods, 'tap/test/script_methods')
131
+ autoload(:Utils, 'tap/test/utils')
113
132
  end
114
133
  end
115
134
 
@@ -6,88 +6,57 @@ module Tap
6
6
  module Test
7
7
 
8
8
 
9
- # FileMethods sets up a TestCase with methods for accessing and utilizing
10
- # test-specific files and directories. Each class that acts_as_file_test
11
- # is set up with a Tap::Root structure (trs) that mediates the creation of
12
- # test method filepaths.
9
+ # FileMethods facilitates access and utilization of test-specific files and
10
+ # directories. FileMethods provides each test method is setup with a Tap::Root
11
+ # (method_root) specific for the method, and defines a new assertion method
12
+ # (assert_files) to facilitate tests which involve the production and/or
13
+ # modification of files.
13
14
  #
15
+ # [file_methods_doc_test.rb]
14
16
  # class FileMethodsDocTest < Test::Unit::TestCase
15
17
  # acts_as_file_test
16
18
  #
17
19
  # def test_something
18
- # # dir = File.expand_path( File.dirname(__FILE__) )
19
- # trs.root # => dir + "/file_methods_doc",
20
- # method_root # => dir + "/file_methods_doc/test_something",
21
- # method_dir(:input) # => dir + "/file_methods_doc/test_something/input"
22
- # end
23
- # end
20
+ # # each test class has a class test root (ctr)
21
+ # # and each test method has a method-specific
22
+ # # root (method_root)
24
23
  #
25
- # === assert_files
24
+ # ctr.root # => File.expand_path(__FILE__.chomp('_test.rb'))
25
+ # method_root.root # => File.join(ctr.root, "/test_something")
26
+ # method_root[:input] # => File.join(ctr.root, "/test_something/input")
26
27
  #
27
- # FileMethods is specifically designed for tests that transform a set of input
28
- # files into output files. For this type of test, input and expected files can
29
- # placed into their respective directories then used within the context of
30
- # assert_files to ensure the output files are equal to the expected files.
31
- #
32
- # For example, lets define a test that transforms input files into output files
33
- # in a trivial way, simply by replacing 'input' with 'output' in the file.
28
+ # # files in the output directory are cleared before
29
+ # # and after each test; this passes each time the
30
+ # # test is run with no additional cleanup:
34
31
  #
35
- # class FileMethodsDocTest < Test::Unit::TestCase
36
- # acts_as_file_test
37
- #
38
- # def test_sub
39
- # assert_files do |input_files|
40
- # input_files.collect do |filepath|
41
- # input = File.read(filepath)
42
- # output_file = method_filepath(:output, File.basename(filepath))
43
- #
44
- # File.open(output_file, "w") do |f|
45
- # f << input.gsub(/input/, "output")
46
- # end
32
+ # output_file = method_root.filepath(:output, 'sample.txt')
33
+ # assert !File.exists?(output_file)
47
34
  #
48
- # output_file
49
- # end
50
- # end
51
- # end
52
- # end
35
+ # make_test_directories # makes the input, output, expected directories
36
+ # FileUtils.touch(output_file)
53
37
  #
54
- # Now say you had some input and expected files for the 'test_sub' method:
38
+ # assert File.exists?(output_file)
55
39
  #
56
- # [file_methods_doc/test_sub/input/one.txt]
57
- # test input 1
40
+ # # the assert_files method compares files produced
41
+ # # by the block the expected files, ensuring they
42
+ # # are the same (see the documentation for the
43
+ # # simplest use of assert_files)
44
+ #
45
+ # expected_file = method_root.filepath(:expected, 'output.txt')
46
+ # File.open(expected_file, 'w') {|file| file << 'expected output' }
58
47
  #
59
- # [file_methods_doc/test_sub/input/two.txt]
60
- # test input 2
61
- #
62
- # [file_methods_doc/test_sub/expected/one.txt]
63
- # test output 1
64
- #
65
- # [file_methods_doc/test_sub/expected/two.txt]
66
- # test output 2
67
- #
68
- # When you run the FileMethodsDocTest test, the test_sub test will pass
69
- # the input files to the assert_files block. Then assert_files compares
70
- # the returned filepaths with the expected files translated from the
71
- # expected directory to the output directory. In this case, the files
72
- # are equal and the test passes.
73
- #
74
- # The test fails if the returned files aren't equal to the expected files,
75
- # either because there are missing or extra files, or if the file contents
76
- # are different.
77
- #
78
- # When the test completes, the teardown method cleans up the output directory.
79
- # For ease in debugging, ENV variable flags can be specified to keep all
80
- # output files (KEEP_OUTPUTS) or to keep the output files for just the tests
81
- # that fail (KEEP_FAILURES). These flags can be specified from the command
82
- # line if you're running the tests with rake or tap:
83
- #
84
- # % rake test keep_outputs=true
85
- # % tap run test keep_failures=true
48
+ # # passes
49
+ # assert_files do
50
+ # output_file = method_root.filepath(:output, 'output.txt')
51
+ # File.open(output_file, 'w') {|file| file << 'expected output' }
86
52
  #
53
+ # output_file
54
+ # end
55
+ # end
56
+ # end
87
57
  #
88
- # === Class Methods
89
- #
90
- # See {Test::Unit::TestCase}[link:classes/Test/Unit/TestCase.html] for documentation of the class methods added by FileMethods.
58
+ # See {Test::Unit::TestCase}[link:classes/Test/Unit/TestCase.html] and
59
+ # FileMethodsClass for more information.
91
60
  module FileMethods
92
61
  include Tap::Test::EnvVars
93
62
 
@@ -96,127 +65,109 @@ module Tap
96
65
  base.extend FileMethodsClass
97
66
  end
98
67
 
99
- # Convenience accessor for the test root structure
100
- def trs
101
- self.class.trs
68
+ # Convenience method to access the class_test_root.
69
+ def ctr
70
+ self.class.class_test_root
102
71
  end
103
-
104
- # Creates the trs.directories, specific to the method calling make_test_directories
72
+
73
+ # Creates the method_root.directories.
105
74
  def make_test_directories
106
- trs.directories.values.each do |dir|
107
- FileUtils.mkdir_p( File.join(trs.root, method_name_str, dir) )
75
+ method_root.directories.values.each do |dir|
76
+ FileUtils.mkdir_p( method_root[dir] )
108
77
  end
109
78
  end
110
79
 
80
+ # Attempts to remove the method_root.directories, method_root.root,
81
+ # and ctr.root. Any given directory will not be removed unless empty.
82
+ def cleanup_test_directories
83
+ method_root.directories.values.each do |dir|
84
+ Utils.try_remove_dir(method_root[dir])
85
+ end
86
+
87
+ Utils.try_remove_dir(method_root.root)
88
+ Utils.try_remove_dir(ctr.root)
89
+ end
90
+
91
+ # The test-method-specific Tap::Root which may be used to
92
+ # access test files. method_root is a duplicate of ctr
93
+ # reconfigured so that method_root.root is ctr[ method_name.to_sym ]
94
+ attr_reader :method_root
95
+
96
+ # An array of filepaths setup by method_tempfile; these files
97
+ # are removed by teardown, as they should all be in the output
98
+ # directory.
111
99
  attr_reader :method_tempfiles
112
100
 
113
- # Setup deletes the the output directory if it exists, and tries to remove the
114
- # method root directory so the directory structure is reset before running the
115
- # test, even if outputs were left over from previous tests.
101
+ # Sets up method_root and attempts to cleanup any left overs from a
102
+ # previous test (ie by deleting method_root[:output] and calling
103
+ # cleanup_test_directories). Be sure to call super when overriding
104
+ # this method.
116
105
  def setup
117
106
  super
107
+ @method_root = ctr.dup.reconfigure(:root => ctr[method_name.to_sym])
118
108
  @method_tempfiles = []
119
- clear_method_dir(:output)
120
- Utils.try_remove_dir(method_root)
109
+
110
+ Utils.clear_dir(method_root[:output])
111
+ cleanup_test_directories
121
112
  end
122
113
 
123
- # Teardown deletes the the output directories unless flagged otherwise. Note
124
- # that teardown also checks the environment variables for flags. To keep all outputs
125
- # (or failures) for all tests, flag keep outputs from the command line like:
114
+ # Deletes the the method_root[:output] directory (unless flagged
115
+ # otherwise by an ENV variable) and calls cleanup_test_directories.
116
+ # To keep all output directories, or to only keep output directories
117
+ # for failing tests, set the 'KEEP_OUTPUTS' or 'KEEP_FAILURES' ENV
118
+ # variables:
126
119
  #
127
- # % tap run test KEEP_OUTPUTS=true
128
- # % tap run test KEEP_FAILURES=true
120
+ # % rap test KEEP_OUTPUTS=true
121
+ # % rap test KEEP_FAILURES=true
122
+ #
123
+ # Be sure to call super when overriding this method.
129
124
  def teardown
130
125
  # clear out the output folder if it exists, unless flagged otherwise
131
126
  unless env("KEEP_OUTPUTS") || (!@test_passed && env("KEEP_FAILURES"))
132
127
  begin
133
- clear_method_dir(:output)
128
+ Utils.clear_dir(method_root[:output])
134
129
  rescue
135
130
  raise("teardown failure: could not remove output files")
136
131
  end
137
132
  end
138
133
 
139
- Utils.try_remove_dir(method_root)
140
- Utils.try_remove_dir(trs.root)
134
+ cleanup_test_directories
141
135
  end
142
136
 
143
137
  # Returns method_name as a string (Ruby 1.9 symbolizes method_name)
144
138
  def method_name_str
145
139
  method_name.to_s
146
140
  end
147
-
148
- # The method_root directory is defined as trs.filepath(method_name)
149
- def method_root(method=method_name_str)
150
- trs.filepath(method)
151
- end
152
-
153
- # The method directory is defined as 'dir/method', where method is the calling method
154
- # by default. method_dir returns the method directory if it exists, otherwise it returns
155
- # trs[dir].
156
- def method_dir(dir, method=method_name_str)
157
- File.join(method_root(method), trs.directories[dir] || dir.to_s)
158
- end
159
-
160
- # Returns a glob of files matching the input pattern, underneath the method directory
161
- # if it exists, otherwise the <tt>trs[dir]</tt> directory.
162
- def method_glob(dir, *patterns)
163
- dir = trs.relative_filepath(:root, method_dir(dir))
164
- trs.glob(dir, *patterns)
165
- end
166
-
167
- # Returns a filepath constructed from the method directory if it exists,
168
- # otherwise the filepath will be constructed from <tt>trs[dir]</tt>.
169
- def method_filepath(dir, *filenames)
170
- File.join(method_dir(dir), *filenames)
171
- end
172
-
173
- # Removes the method directory from the input filepath, returning the resuting filename.
174
- # If the method directory does not exist, <tt>trs[dir]</tt> will be removed.
175
- def method_relative_filepath(dir, filepath)
176
- dir = trs.relative_filepath(:root, method_dir(dir))
177
- trs.relative_filepath(dir, filepath)
178
- end
179
141
 
180
- # Returns an output file corresponding to the input file, translated from the
181
- # input directory to the output directory.
142
+ # Generates a temporary filepath formatted like "output_dir\filename.n.ext"
143
+ # where n is a counter that ensures the filepath is unique and non-existant
144
+ # (specificaly n is equal to the number of method_tempfiles generated
145
+ # by the current test, incremented as necessary to achieve a non-existant
146
+ # filepath).
182
147
  #
183
- # If the input method directory exists, it will be removed from the filepath.
184
- # If the output method directory exists, it will be inserted in the filepath.
185
- def method_translate(filepath, input_dir, output_dir)
186
- input_dir = trs.relative_filepath(:root, method_dir(input_dir))
187
- output_dir = trs.relative_filepath(:root, method_dir(output_dir))
188
- trs.translate(filepath, input_dir, output_dir)
189
- end
190
-
191
- # Attempts to recursively remove the specified method directory and all
192
- # files within it. Raises an error if the removal does not succeed.
193
- def clear_method_dir(dir)
194
- # clear out the folder if it exists
195
- dir_path = method_dir(dir, method_name_str)
196
- FileUtils.rm_r(dir_path) if File.exists?(dir_path)
197
- end
198
-
199
- # Generates a temporary filepath formatted like "output_dir\filename.pid.n.ext" where n
200
- # is a counter that will be incremented from until a non-existant filepath is achieved.
148
+ # Unlike Tempfile, method_tempfile does not create the filepath unless a
149
+ # block is given, in which case an open File will be passed to the block.
150
+ # In addition, method_tempfiles are only cleaned up indirectly when the
151
+ # output directory is removed by teardown; this is both convenient for
152
+ # testing (when you may want a the file to persist, so you can debug it)
153
+ # and less enforcing than Tempfile.
201
154
  #
202
155
  # Notes:
203
- # - By default filename is the calling method
204
- # - The extension is chomped off the end of the filename
205
- # - If the directory for the filepath does not exist, the directory will be created
206
- # - Like all files in the output directory, tempfiles will be deleted by the default
207
- # +teardown+ method
156
+ # - by default filename is the calling method
157
+ # - the extension is chomped off the end of the filename
158
+ # - the directory for the file will be created if it does not exist
159
+ # - like all files in the output directory, tempfiles will be deleted by
160
+ # the default +teardown+ method
208
161
  def method_tempfile(filename=method_name_str, &block)
209
162
  ext = File.extname(filename)
210
163
  basename = filename.chomp(ext)
211
- filepath = method_filepath(:output, sprintf('%s%d.%d%s', basename, $$, method_tempfiles.length, ext))
212
- method_tempfiles << filepath
213
-
214
- dirname = File.dirname(filepath)
164
+ path = next_indexed_path(method_root.filepath(:output, basename), method_tempfiles.length, ext)
165
+ dirname = File.dirname(path)
166
+
167
+ method_tempfiles << path
215
168
  FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
216
- if block_given?
217
- File.open(filepath, "w", &block)
218
- end
219
- filepath
169
+ File.open(path, "w", &block) if block_given?
170
+ path
220
171
  end
221
172
 
222
173
  # assert_files runs a file-based test that feeds all files from input_dir
@@ -225,33 +176,90 @@ module Tap
225
176
  # the block are used in the comparison; additional files in the output directory
226
177
  # are effectively ignored.
227
178
  #
228
- # A variety of options can be specified to adjust the behavior:
179
+ # === Example
180
+ # Lets define a test that transforms input files into output files in a trivial
181
+ # way, simply by replacing 'input' with 'output' in the file.
182
+ #
183
+ # class FileMethodsDocTest < Test::Unit::TestCase
184
+ # acts_as_file_test
185
+ #
186
+ # def test_sub
187
+ # assert_files do |input_files|
188
+ # input_files.collect do |filepath|
189
+ # input = File.read(filepath)
190
+ # output_file = method_root.filepath(:output, File.basename(filepath))
191
+ #
192
+ # File.open(output_file, "w") do |f|
193
+ # f << input.gsub(/input/, "output")
194
+ # end
195
+ #
196
+ # output_file
197
+ # end
198
+ # end
199
+ # end
200
+ # end
201
+ #
202
+ # Now say you had some input and expected files for the 'test_sub' method:
203
+ #
204
+ # file_methods_doc/test_sub
205
+ # |- expected
206
+ # | |- one.txt
207
+ # | `- two.txt
208
+ # `- input
209
+ # |- one.txt
210
+ # `- two.txt
211
+ #
212
+ # [input/one.txt]
213
+ # test input 1
214
+ #
215
+ # [input/two.txt]
216
+ # test input 2
217
+ #
218
+ # [expected/one.txt]
219
+ # test output 1
220
+ #
221
+ # [expected/two.txt]
222
+ # test output 2
223
+ #
224
+ # When you run the test, the assert_files passes the input files to the
225
+ # block. When the block completes, assert_files compares the output files
226
+ # returned by the block with the files in the expected directory. In this
227
+ # case, the files are equal and the test passes.
228
+ #
229
+ # Say you changed the content of one of the expected files:
230
+ #
231
+ # [expected/one.txt]
232
+ # test flunk 1
233
+ #
234
+ # Now the test fails because the output files aren't equal to the expected
235
+ # files. The test will also fail if there are missing or extra files.
236
+ #
237
+ # === Options
238
+ # A variety of options can be specified to adjust the behavior of assert_files:
229
239
  #
230
240
  # :input_dir specify the directory to glob for input files
231
- # (default method_dir(:input))
241
+ # (default method_root[:input])
232
242
  # :output_dir specify the output directory
233
- # (default method_dir(:output))
243
+ # (default method_root[:output])
234
244
  # :expected_dir specify the directory to glob for expected files
235
- # (default method_dir(:expected))
236
- # :input_files directly specify the input files to pass to the block
237
- # :expected_files directly specify the expected files used for comparison
245
+ # (default method_root[:expected])
246
+ # :input_files directly specify the input files for the block
247
+ # :expected_files directly specify the expected files for comparison
238
248
  # :include_input_directories specifies directories to be included in the
239
249
  # input_files array (by default dirs are excluded)
240
250
  # :include_expected_directories specifies directories to be included in the
241
- # expected-output file list comparison (by default
242
- # dirs are excluded, note that naturally only files
243
- # have their actual content compared)
251
+ # expected-output file list comparison
252
+ # (by default dirs are excluded)
244
253
  #
245
- # Option keys should be symbols. assert_files will fail if :expected_files was
246
- # not specified in the options and no files were found in method_dir(:expected).
247
- # This tries to prevent silent false-positive results when you forget to put
248
- # expected files in their place.
254
+ # assert_files will fail if <tt>:expected_files</tt> was not specified in the
255
+ # options and no files were found in <tt>:expected_dir</tt>. This check tries
256
+ # to prevent silent false-positive results when you forget to put expected files
257
+ # in their place.
249
258
  #
250
259
  # === File References
251
- # Sometimes the same files will get used across multiple tests. To prevent
252
- # duplication, and allow separate management of test files, file references
253
- # can be provided in place of test files. For instance, with a test
254
- # directory like:
260
+ # Sometimes the same files will get used across multiple tests. To allow separate
261
+ # management of test files and prevent duplication, file references can be provided
262
+ # in place of test files. For instance, with a test directory like:
255
263
  #
256
264
  # method_root
257
265
  # |- expected
@@ -267,20 +275,30 @@ module Tap
267
275
  # The input and expected files (all references in this case) can be dereferenced
268
276
  # to the 'ref' filepaths like so:
269
277
  #
270
- # assert_files :reference_dir => method_dir(:ref) do |input_files|
278
+ # assert_files :reference_dir => method_root[:ref] do |input_files|
271
279
  # input_files # => ['method_root/ref/one.txt', 'method_root/ref/two.txt']
272
280
  #
273
281
  # input_files.collect do |input_file|
274
- # output_file = method_filepath(:output, File.basename(input_file)
282
+ # output_file = method_root.filepath(:output, File.basename(input_file)
275
283
  # FileUtils.cp(input_file, output_file)
276
284
  # output_file
277
285
  # end
278
286
  # end
279
287
  #
280
288
  # Dereferencing occurs relative to the input_dir/expected_dir configurations; a
281
- # reference_dir must be specified for dereferencing to occur (see dereference
289
+ # reference_dir must be specified for dereferencing to occur (see Utils.dereference
282
290
  # for more details).
283
291
  #
292
+ # === Keeping Outputs
293
+ # By default FileMethods sets teardown to cleans up the output directory. For
294
+ # ease in debugging, ENV variable flags can be specified to keep all output
295
+ # files (KEEP_OUTPUTS) or to keep the output files for just the tests that fail
296
+ # (KEEP_FAILURES). These flags can be specified from the command line if you're
297
+ # running the tests with rake or rap:
298
+ #
299
+ # % rake test keep_outputs=true
300
+ # % rap test keep_failures=true
301
+ #
284
302
  #--
285
303
  # TODO:
286
304
  # * add debugging information to indicate, for instance,
@@ -294,9 +312,9 @@ module Tap
294
312
  expected_dir = options[:expected_dir]
295
313
 
296
314
  reference_dir = options[:reference_dir]
297
- reference_extname = options[:reference_extname]
315
+ reference_pattern = options[:reference_pattern]
298
316
 
299
- Utils.dereference([input_dir, expected_dir], reference_dir, reference_extname) do
317
+ Utils.dereference([input_dir, expected_dir], reference_dir, reference_pattern || '**/*.ref') do
300
318
 
301
319
  # Get the input and expected files in this manner:
302
320
  # - look for manually specified files
@@ -348,9 +366,9 @@ module Tap
348
366
  # The default assert_files options
349
367
  def default_assert_files_options
350
368
  {
351
- :input_dir => method_dir(:input),
352
- :output_dir => method_dir(:output),
353
- :expected_dir => method_dir(:expected),
369
+ :input_dir => method_root[:input],
370
+ :output_dir => method_root[:output],
371
+ :expected_dir => method_root[:expected],
354
372
 
355
373
  :input_files => nil,
356
374
  :expected_files => nil,
@@ -362,6 +380,14 @@ module Tap
362
380
  }
363
381
  end
364
382
 
383
+ private
384
+
385
+ # utility method for method_tempfile; increments index until the
386
+ # path base.indexext does not exist.
387
+ def next_indexed_path(base, index, ext) # :nodoc:
388
+ path = sprintf('%s.%d%s', base, index, ext)
389
+ File.exists?(path) ? next_indexed_path(base, index + 1, ext) : path
390
+ end
365
391
  end
366
392
  end
367
393
  end