bahuvrihi-tap 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ module Tap
2
+ module Support
3
+ module CommandLine
4
+ class Parser
5
+ class << self
6
+ def parse_sequence(str, count=0)
7
+ seq = []
8
+ seq << count if str[0] == ?:
9
+ str.split(/:+/).each do |n|
10
+ seq << n.to_i unless n.empty?
11
+ end
12
+ seq << count + 1 if str[-1] == ?:
13
+ seq
14
+ end
15
+
16
+ def bracket_regexp(l, r)
17
+ /\A--(\d*)#{Regexp.escape(l)}([\d,]*)#{Regexp.escape(r)}\z/
18
+ end
19
+
20
+ def parse_bracket(lead, str, count=0)
21
+ bracket = []
22
+ str.split(/,+/).each do |n|
23
+ bracket << n.to_i unless n.empty?
24
+ end
25
+
26
+ [lead.empty? ? count : lead.to_i, bracket]
27
+ end
28
+
29
+ # Parses the input string as YAML, if the string matches the YAML document
30
+ # specifier (ie it begins with "---\s*\n"). Otherwise returns the string.
31
+ #
32
+ # str = {'key' => 'value'}.to_yaml # => "--- \nkey: value\n"
33
+ # Tap::Script.parse_yaml(str) # => {'key' => 'value'}
34
+ # Tap::Script.parse_yaml("str") # => "str"
35
+ def parse_yaml(str)
36
+ str =~ /\A---\s*\n/ ? YAML.load(str) : str
37
+ end
38
+
39
+ def shift_arg(argv)
40
+ index = nil
41
+ argv.each_with_index do |arg, i|
42
+ if arg !~ /\A-/
43
+ index = i
44
+ break
45
+ end
46
+ end
47
+ index == nil ? nil : argv.delete_at(index)
48
+ end
49
+ end
50
+
51
+ ROUND = /\A--(\+(\d+)|\+*)\z/
52
+ SEQUENCE = /\A--(\d*(:\d*)+)\z/
53
+ FORK = bracket_regexp("[", "]")
54
+ MERGE = bracket_regexp("{", "}")
55
+ SYNC_MERGE = bracket_regexp("(", ")")
56
+ INVALID = /\A--(\z|[^A-Za-z])/
57
+
58
+ attr_reader :rounds
59
+ attr_reader :sequences
60
+ attr_reader :forks
61
+ attr_reader :merges
62
+ attr_reader :sync_merges
63
+
64
+ def initialize(argv)
65
+ @sequences = []
66
+ @forks = []
67
+ @merges = []
68
+ @sync_merges = []
69
+
70
+ current = []
71
+ current_round = []
72
+ count = 0
73
+ @rounds = [current_round]
74
+
75
+ argv.each do |arg|
76
+ unless arg =~ INVALID
77
+ current << arg
78
+ next
79
+ end
80
+
81
+ # for peformance split to match
82
+ # most arguments just once.
83
+ current_round << current unless current.empty?
84
+ current = []
85
+
86
+ case arg
87
+ when ROUND
88
+ current_round = (@rounds[$2 ? $2.to_i : $1.length] ||= [])
89
+ when SEQUENCE
90
+ @sequences << Parser.parse_sequence($1, count)
91
+ when FORK
92
+ @forks << Parser.parse_bracket($1, $2, count)
93
+ when MERGE
94
+ @merges << Parser.parse_bracket($1, $2, count)
95
+ when SYNC_MERGE
96
+ @sync_merges << Parser.parse_bracket($1, $2, count)
97
+ else
98
+ raise ArgumentError, "invalid argument: #{arg}"
99
+ end
100
+
101
+ count += 1
102
+ end
103
+
104
+ current_round << current unless current.empty?
105
+ @rounds.delete_if {|round| round.nil? || round.empty? }
106
+ end
107
+
108
+ def targets
109
+ targets = []
110
+ sequences.each {|sequence| targets.concat(sequence[1..-1]) }
111
+ forks.each {|fork| targets.concat(fork[1]) }
112
+ targets.concat merges.collect {|target, sources| target }
113
+ targets.concat sync_merges.collect {|target, sources| target }
114
+
115
+ targets.uniq.sort
116
+ end
117
+
118
+ end
119
+ end
120
+ end
121
+ end
@@ -57,7 +57,7 @@ module Tap
57
57
  caller.each_with_index do |line, index|
58
58
  case line
59
59
  when /\/configurable.rb/ then next
60
- when /^(([A-z]:)?[^:]+):(\d+)/
60
+ when Lazydoc::CALLER_REGEXP
61
61
  base.instance_variable_set(:@source_file, File.expand_path($1))
62
62
  break
63
63
  end
@@ -71,7 +71,7 @@ module Tap
71
71
  # the configurations of the parent class.
72
72
  def inherited(child)
73
73
  unless child.instance_variable_defined?(:@source_file)
74
- caller.first =~ /^(([A-z]:)?[^:]+):(\d+)/
74
+ caller.first =~ Lazydoc::CALLER_REGEXP
75
75
  child.instance_variable_set(:@source_file, File.expand_path($1))
76
76
  end
77
77
 
@@ -250,7 +250,7 @@ module Tap
250
250
  caller.each do |line|
251
251
  case line
252
252
  when /in .config.$/ then next
253
- when /^(([A-z]:)?[^:]+):(\d+)/
253
+ when Lazydoc::CALLER_REGEXP
254
254
  options[:desc] = Lazydoc.register($1, $3.to_i - 1)
255
255
  break
256
256
  end
@@ -49,7 +49,7 @@ module Tap
49
49
  def config(key, value=nil, options={}, &block)
50
50
  caller.each do |line|
51
51
  case line
52
- when /^(([A-z]:)?[^:]+):(\d+)/
52
+ when Lazydoc::CALLER_REGEXP
53
53
  options[:desc] = Support::Lazydoc.register($1, $3.to_i - 1)
54
54
  break
55
55
  end
@@ -61,7 +61,7 @@ module Tap
61
61
  def config_attr(key, value=nil, options={}, &block)
62
62
  caller.each do |line|
63
63
  case line
64
- when /^(([A-z]:)?[^:]+):(\d+)/
64
+ when Lazydoc::CALLER_REGEXP
65
65
  options[:desc] = Support::Lazydoc.register($1, $3.to_i - 1)
66
66
  break
67
67
  end
@@ -13,7 +13,7 @@ module Tap
13
13
  caller.each do |line|
14
14
  case line
15
15
  when /\/framework.rb/ then next
16
- when /^(([A-z]:)?[^:]+):(\d+)/
16
+ when Lazydoc::CALLER_REGEXP
17
17
  base.instance_variable_set(:@source_file, File.expand_path($1))
18
18
  break
19
19
  end
@@ -24,7 +24,7 @@ module Tap
24
24
 
25
25
  def inherited(child)
26
26
  unless child.instance_variable_defined?(:@source_file)
27
- caller.first =~ /^(([A-z]:)?[^:]+):(\d+)/
27
+ caller.first =~ Lazydoc::CALLER_REGEXP
28
28
  child.instance_variable_set(:@source_file, File.expand_path($1))
29
29
  end
30
30
 
@@ -64,7 +64,7 @@ module Tap
64
64
  caller.each_with_index do |line, index|
65
65
  case line
66
66
  when /\/tap\/support\/declarations.rb/ then next
67
- when /^(([A-z]:)?[^:]+):(\d+)/
67
+ when Lazydoc::CALLER_REGEXP
68
68
  subclass.source_file = File.expand_path($1)
69
69
  lzd = subclass.lazydoc(false)
70
70
  lzd[const_name, false]['manifest'] = lzd.register($3.to_i - 1)
@@ -162,8 +162,10 @@ module Tap
162
162
  end
163
163
  path_configs = path_configs[0]
164
164
  end
165
+
166
+ argv = (argv + use_args).collect {|str| str =~ /\A---\s*\n/ ? YAML.load(str) : str }
165
167
 
166
- [obj.reconfigure(path_configs).reconfigure(config), argv + use_args]
168
+ [obj.reconfigure(path_configs).reconfigure(config), argv]
167
169
  end
168
170
 
169
171
  def lazydoc(resolve=true)
@@ -59,9 +59,9 @@ module Tap
59
59
  super
60
60
  end
61
61
 
62
- def have_rakefile(indir=nil)
63
- return super() if indir == nil
64
- Tap::Root.indir(indir) { super() }
62
+ def have_rakefile(dir=nil)
63
+ return super() if dir == nil
64
+ Tap::Root.chdir(dir) { super() }
65
65
  end
66
66
 
67
67
  protected
@@ -86,5 +86,5 @@ end
86
86
  end
87
87
 
88
88
  Rake.application.extend Tap::Support::Gems::Rake
89
- Tap::Env.manifests[:rakefiles] = Tap::Support::RakeManifest
89
+ Tap::Env.manifests[:rakefiles] = Tap::Support::Gems::RakeManifest
90
90
 
@@ -122,7 +122,7 @@ module Tap
122
122
  #
123
123
  class Lazydoc
124
124
 
125
- # A regexp matching an attribute start or end. For the match:
125
+ # A regexp matching an attribute start or end. After a match:
126
126
  #
127
127
  # $1:: const_name
128
128
  # $3:: key
@@ -133,6 +133,15 @@ module Tap
133
133
  # A regexp matching constants from the ATTRIBUTE_REGEXP leader
134
134
  CONSTANT_REGEXP = /#.*?([A-Z][A-z]*(::[A-Z][A-z]*)*)?$/
135
135
 
136
+ # A regexp matching a caller line, to extract the calling file
137
+ # and line number. After a match:
138
+ #
139
+ # $1:: file
140
+ # $3:: line number (as a string, obviously)
141
+ #
142
+ # Note that line numbers in caller start at 1, not 0.
143
+ CALLER_REGEXP = /^(([A-z]:)?[^:]+):(\d+)/
144
+
136
145
  class << self
137
146
 
138
147
  # A hash of (source_file, lazydoc) pairs tracking the
data/lib/tap/test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'tap/test/tap_methods'
1
+ require 'test/unit'
2
2
 
3
3
  module Test # :nodoc:
4
4
  module Unit # :nodoc:
@@ -19,6 +19,84 @@ module Test # :nodoc:
19
19
  #--
20
20
  #See the TestTutorial for more information.
21
21
  class TestCase
22
+ class << self
23
+
24
+ def inherited(child)
25
+ child.instance_variable_set(:@skip_messages, [])
26
+ child.instance_variable_set(:@run_test_suite, true)
27
+ end
28
+
29
+ #
30
+ # Methods for skipping a test suite
31
+ #
32
+
33
+ attr_accessor :run_test_suite
34
+
35
+ # Causes a test suite to be skipped. If a message is given, it will
36
+ # print and notify the user the test suite has been skipped.
37
+ def skip_test(msg=nil)
38
+ self.run_test_suite = false
39
+
40
+ # experimental -- perhaps use this so that a test can be skipped
41
+ # for multiple reasons?
42
+ @skip_messages << msg
43
+ end
44
+
45
+ alias :original_suite :suite
46
+
47
+ # Modifies the default suite method to include/exclude tests based on platform.
48
+ def suite # :nodoc:
49
+ if run_test_suite
50
+ original_suite
51
+ else
52
+ skip_message = @skip_messages.compact.join(', ')
53
+ puts "Skipping #{name}#{skip_message.empty? ? '' : ': ' + skip_message}"
54
+ Test::Unit::TestSuite.new(name)
55
+ end
56
+ end
57
+
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.
63
+ #
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.
67
+ def acts_as_file_test(options={})
68
+ include Tap::Test::FileMethods
69
+
70
+ options = {
71
+ :root => file_test_root,
72
+ :directories => {:input => 'input', :output => 'output', :expected => 'expected'}
73
+ }.merge(options)
74
+ self.trs = Tap::Root.new(options[:root], options[:directories])
75
+ end
76
+
77
+ # Causes a unit test to act as a tap test -- resulting in the following:
78
+ # - setup using acts_as_file_test
79
+ # - inclusion of Tap::Test::SubsetMethods
80
+ # - inclusion of Tap::Test::InstanceMethods
81
+ #
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.
85
+ def acts_as_tap_test(options={})
86
+ include Tap::Test::SubsetMethods
87
+ include Tap::Test::FileMethods
88
+ include Tap::Test::TapMethods
89
+
90
+ acts_as_file_test({:root => file_test_root}.merge(options))
91
+ end
92
+
93
+ def acts_as_script_test(options={})
94
+ include Tap::Test::FileMethods
95
+ include Tap::Test::ScriptMethods
96
+
97
+ acts_as_file_test({:root => file_test_root}.merge(options))
98
+ end
99
+ end
22
100
  end
23
101
  end
24
102
  end
@@ -29,6 +107,9 @@ module Tap
29
107
  # Tap, but SubsetMethods and FileMethods are more general in
30
108
  # their utility.
31
109
  module Test
110
+ autoload(:SubsetMethods, 'tap/test/subset_methods')
111
+ autoload(:FileMethods, 'tap/test/file_methods')
112
+ autoload(:TapMethods, 'tap/test/tap_methods')
32
113
  end
33
114
  end
34
115
 
@@ -22,7 +22,7 @@ module Tap
22
22
 
23
23
  # Returns true if the env_var(var) is set and matches /^true$/i
24
24
  def env_true?(var)
25
- env(var) && env(var) =~ /^true$/i
25
+ (env(var) && env(var) =~ /^true$/i) ? true : false
26
26
  end
27
27
  end
28
28
  end
@@ -1,57 +1,6 @@
1
- require 'tap/root'
1
+ require 'tap/test/utils'
2
2
  require 'tap/test/env_vars'
3
- require 'test/unit'
4
- require 'fileutils'
5
-
6
- module Test # :nodoc:
7
- module Unit # :nodoc:
8
- class TestCase
9
- class << self
10
-
11
- # Access the test root structure (a Tap::Root)
12
- attr_accessor :trs
13
-
14
- # Causes a TestCase to act as a file test, by instantiating a class Tap::Root
15
- # (trs), and including FileMethods. The root and directories used to
16
- # instantiate trs can be specified as options. By default file_test_root
17
- # and the directories {:input => 'input', :output => 'output', :expected => 'expected'}
18
- # will be used.
19
- #
20
- # Note: file_test_root determines a root directory <em>based on the calling file</em>.
21
- # Be sure to specify the root directory explicitly if you call acts_as_file_test
22
- # from a file that is NOT meant to be test file.
23
- def acts_as_file_test(options={})
24
- options = {
25
- :root => file_test_root,
26
- :directories => {:input => 'input', :output => 'output', :expected => 'expected'}
27
- }.merge(options)
28
-
29
- directories = options[:directories]
30
- self.trs = Tap::Root.new(options[:root], directories)
31
-
32
- include Tap::Test::FileMethods
33
- end
34
-
35
- # Infers the test root directory from the calling file. Ex:
36
- # 'some_class.rb' => 'some_class'
37
- # 'some_class_test.rb' => 'some_class'
38
- def file_test_root
39
- # the calling file is not the direct caller of +method_root+... this method is
40
- # only accessed from within another method call, hence the target caller is caller[1]
41
- # rather than caller[0].
42
-
43
- # caller[1] is considered the calling file (which should be the test case)
44
- # note that the output of calller.first is like:
45
- # ./path/to/file.rb:10
46
- # ./path/to/file.rb:10:in 'method'
47
- calling_file = caller[1].gsub(/:\d+(:in .*)?$/, "")
48
- calling_file.chomp!("#{File.extname(calling_file)}")
49
- calling_file.chomp("_test")
50
- end
51
- end
52
- end
53
- end
54
- end
3
+ require 'tap/test/file_methods_class'
55
4
 
56
5
  module Tap
57
6
  module Test
@@ -141,7 +90,12 @@ module Tap
141
90
  # See {Test::Unit::TestCase}[link:classes/Test/Unit/TestCase.html] for documentation of the class methods added by FileMethods.
142
91
  module FileMethods
143
92
  include Tap::Test::EnvVars
144
-
93
+
94
+ def self.included(base)
95
+ super
96
+ base.extend FileMethodsClass
97
+ end
98
+
145
99
  # Convenience accessor for the test root structure
146
100
  def trs
147
101
  self.class.trs
@@ -163,7 +117,7 @@ module Tap
163
117
  super
164
118
  @method_tempfiles = []
165
119
  clear_method_dir(:output)
166
- try_remove_dir(method_root)
120
+ Utils.try_remove_dir(method_root)
167
121
  end
168
122
 
169
123
  # Teardown deletes the the output directories unless flagged otherwise. Note
@@ -182,8 +136,8 @@ module Tap
182
136
  end
183
137
  end
184
138
 
185
- try_remove_dir(method_root)
186
- try_remove_dir(trs.root)
139
+ Utils.try_remove_dir(method_root)
140
+ Utils.try_remove_dir(trs.root)
187
141
  end
188
142
 
189
143
  # Returns method_name as a string (Ruby 1.9 symbolizes method_name)
@@ -241,18 +195,6 @@ module Tap
241
195
  dir_path = method_dir(dir, method_name_str)
242
196
  FileUtils.rm_r(dir_path) if File.exists?(dir_path)
243
197
  end
244
-
245
- # Attempts to remove the specified directory. The root
246
- # will not be removed if the directory does not exist, or
247
- # is not empty.
248
- def try_remove_dir(dir)
249
- # Remove the directory if possible
250
- begin
251
- FileUtils.rmdir(dir) if File.exists?(dir) && Dir.glob(File.join(dir, "*")).empty?
252
- rescue
253
- # rescue cases where there is a hidden file, for example .svn
254
- end
255
- end
256
198
 
257
199
  # Generates a temporary filepath formatted like "output_dir\filename.pid.n.ext" where n
258
200
  # is a counter that will be incremented from until a non-existant filepath is achieved.
@@ -277,36 +219,22 @@ module Tap
277
219
  filepath
278
220
  end
279
221
 
280
- # Yields to the input block for each pair of entries in the input
281
- # arrays. An error is raised if the input arrays do not have equal
282
- # numbers of entries.
283
- def each_pair(a, b, &block) # :yields: entry_a, entry_b,
284
- each_pair_with_index(a,b) do |entry_a, entry_b, index|
285
- yield(entry_a, entry_b)
286
- end
287
- end
288
-
289
- # Same as each_pair but yields the index of the entries as well.
290
- def each_pair_with_index(a, b, &block) # :yields: entry_a, entry_b, index
291
- a = [a] unless a.kind_of?(Array)
292
- b = [b] unless b.kind_of?(Array)
293
-
294
- raise ArgumentError, "The input arrays must have an equal number of entries." unless a.length == b.length
295
- 0.upto(a.length-1) do |index|
296
- yield(a[index], b[index], index)
297
- end
298
- end
299
-
300
- # assert_files runs a file-based test that feeds all files in method_dir(:input)
222
+ # assert_files runs a file-based test that feeds all files from input_dir
301
223
  # to the block, then compares the resulting files (which should be relative to
302
- # method_dir(:output)) with all the files in method_dir(:expected). Note that
303
- # since only the files returned by the block are used in the comparison,
304
- # additional files in the output directory are effectively ignored.
224
+ # output_dir) with all the files in expected_dir. Only the files returned by
225
+ # the block are used in the comparison; additional files in the output directory
226
+ # are effectively ignored.
305
227
  #
306
228
  # A variety of options can be specified to adjust the behavior:
307
229
  #
308
- # :input_files specify the input files to pass to the block
309
- # :expected_files specify the expected files used in comparison
230
+ # :input_dir specify the directory to glob for input files
231
+ # (default method_dir(:input))
232
+ # :output_dir specify the output directory
233
+ # (default method_dir(:output))
234
+ # :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
310
238
  # :include_input_directories specifies directories to be included in the
311
239
  # input_files array (by default dirs are excluded)
312
240
  # :include_expected_directories specifies directories to be included in the
@@ -318,60 +246,122 @@ module Tap
318
246
  # not specified in the options and no files were found in method_dir(:expected).
319
247
  # This tries to prevent silent false-positive results when you forget to put
320
248
  # expected files in their place.
249
+ #
250
+ # === 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:
255
+ #
256
+ # method_root
257
+ # |- expected
258
+ # | |- one.txt.ref
259
+ # | `- two.txt.ref
260
+ # |- input
261
+ # | |- one.txt.ref
262
+ # | `- two.txt.ref
263
+ # `- ref
264
+ # |- one.txt
265
+ # `- two.txt
266
+ #
267
+ # The input and expected files (all references in this case) can be dereferenced
268
+ # to the 'ref' filepaths like so:
269
+ #
270
+ # assert_files :reference_dir => method_dir(:ref) do |input_files|
271
+ # input_files # => ['method_root/ref/one.txt', 'method_root/ref/two.txt']
272
+ #
273
+ # input_files.collect do |input_file|
274
+ # output_file = method_filepath(:output, File.basename(input_file)
275
+ # FileUtils.cp(input_file, output_file)
276
+ # output_file
277
+ # end
278
+ # end
279
+ #
280
+ # Dereferencing occurs relative to the input_dir/expected_dir configurations; a
281
+ # reference_dir must be specified for dereferencing to occur (see dereference
282
+ # for more details).
283
+ #
284
+ #--
285
+ # TODO:
286
+ # * add debugging information to indicate, for instance,
287
+ # when dereferencing is going on.
321
288
  def assert_files(options={}) # :yields: input_files
322
289
  make_test_directories
323
290
 
324
- options = {
325
- :input_files => nil,
326
- :expected_files => nil,
327
-
328
- :include_input_directories => false,
329
- :include_expected_directories => false
330
- }.merge(options)
291
+ options = default_assert_files_options.merge(options)
292
+ input_dir = options[:input_dir]
293
+ output_dir = options[:output_dir]
294
+ expected_dir = options[:expected_dir]
331
295
 
332
- # Get the input and expected files in this manner:
333
- # - look for manually specified files
334
- # - glob for files if none were specified
335
- # - expand paths and sort
336
- # - remove directories unless specified not to do so
337
- input_files, expected_files = [:input, :expected].collect do |key|
338
- files = options["#{key}_files".to_sym]
339
- files = method_glob(key) if files.nil?
340
- files = [files].flatten.collect {|file| File.expand_path(file) }.sort
296
+ reference_dir = options[:reference_dir]
297
+ reference_extname = options[:reference_extname]
298
+
299
+ Utils.dereference([input_dir, expected_dir], reference_dir, reference_extname) do
341
300
 
342
- unless options["include_#{key}_directories".to_sym]
343
- files.delete_if {|file| File.directory?(file)}
344
- end
301
+ # Get the input and expected files in this manner:
302
+ # - look for manually specified files
303
+ # - glob for files if none were specified
304
+ # - expand paths and sort
305
+ # - remove directories unless specified not to do so
306
+ input_files, expected_files = [:input, :expected].collect do |key|
307
+ files = options["#{key}_files".to_sym]
308
+ if files.nil?
309
+ pattern = File.join(options["#{key}_dir".to_sym], "**/*")
310
+ files = Dir.glob(pattern)
311
+ end
312
+ files = [files].flatten.collect {|file| File.expand_path(file) }.sort
313
+
314
+ unless options["include_#{key}_directories".to_sym]
315
+ files.delete_if {|file| File.directory?(file)}
316
+ end
345
317
 
346
- files
347
- end
318
+ files
319
+ end
348
320
 
349
- # check at least one expected file was found
350
- if expected_files.empty? && options[:expected_files] == nil
351
- flunk "No expected files specified."
352
- end
353
-
354
- # get output files from the block, expand and sort
355
- output_files = [yield(input_files)].flatten.collect do |output_file|
356
- output_file = File.expand_path(output_file)
357
- end.sort
321
+ # check at least one expected file was found
322
+ if expected_files.empty? && options[:expected_files] == nil
323
+ flunk "No expected files specified."
324
+ end
358
325
 
359
- # check that the expected and output filepaths are the same
360
- translated_expected_files = expected_files.collect do |expected_file|
361
- method_translate(expected_file, :expected, :output)
362
- end
363
- assert_equal translated_expected_files, output_files, "Missing, extra, or unexpected output files"
364
-
365
- # check that the expected and output file contents are equal
366
- errors = []
367
- each_pair(expected_files, output_files) do |expected_file, output_file|
368
- unless (File.directory?(expected_file) && File.directory?(output_file)) || FileUtils.cmp(expected_file, output_file)
369
- errors << "<#{expected_file}> not equal to\n<#{output_file}>"
326
+ # get output files from the block, expand and sort
327
+ output_files = [yield(input_files)].flatten.collect do |output_file|
328
+ File.expand_path(output_file)
329
+ end.sort
330
+
331
+ # check that the expected and output filepaths are the same
332
+ translated_expected_files = expected_files.collect do |expected_file|
333
+ Tap::Root.translate(expected_file, expected_dir, output_dir)
370
334
  end
335
+ assert_equal translated_expected_files, output_files, "Missing, extra, or unexpected output files"
336
+
337
+ # check that the expected and output file contents are equal
338
+ errors = []
339
+ Utils.each_pair(expected_files, output_files) do |expected_file, output_file|
340
+ unless (File.directory?(expected_file) && File.directory?(output_file)) || FileUtils.cmp(expected_file, output_file)
341
+ errors << "<#{expected_file}> not equal to\n<#{output_file}>"
342
+ end
343
+ end
344
+ flunk "File compare failed:\n" + errors.join("\n") unless errors.empty?
371
345
  end
372
- flunk "File compare failed:\n" + errors.join("\n") unless errors.empty?
373
346
  end
374
-
347
+
348
+ # The default assert_files options
349
+ def default_assert_files_options
350
+ {
351
+ :input_dir => method_dir(:input),
352
+ :output_dir => method_dir(:output),
353
+ :expected_dir => method_dir(:expected),
354
+
355
+ :input_files => nil,
356
+ :expected_files => nil,
357
+ :include_input_directories => false,
358
+ :include_expected_directories => false,
359
+
360
+ :reference_dir => nil,
361
+ :reference_extname => '.ref'
362
+ }
363
+ end
364
+
375
365
  end
376
366
  end
377
367
  end