Module: Tap::Test::FileTest
- Includes:
- Assertions, EnvVars
- Defined in:
- lib/tap/test/file_test.rb
Overview
FileTest facilitates access and utilization of test-specific files and directories. FileTest provides each test method is setup with a Tap::Root (method_root) specific for the method, and defines a new assertion method (assert_files) to facilitate tests which involve the production and/or modification of files.
[file_test_doc_test.rb]
class FileTestDocTest < Test::Unit::TestCase
acts_as_file_test
def test_something
# each test class has a class test root (ctr)
# and each test method has a method-specific
# root (method_root)
ctr.root # => File.expand_path(__FILE__.chomp('_test.rb'))
method_root.root # => File.join(ctr.root, "/test_something")
method_root[:input] # => File.join(ctr.root, "/test_something/input")
# files in the output directory are cleared before
# and after each test; this passes each time the
# test is run with no additional cleanup:
output_file = method_root.filepath(:output, 'sample.txt')
assert !File.exists?(output_file)
make_test_directories # makes the input, output, expected directories
FileUtils.touch(output_file)
assert File.exists?(output_file)
# the assert_files method compares files produced
# by the block the expected files, ensuring they
# are the same (see the documentation for the
# simplest use of assert_files)
expected_file = method_root.filepath(:expected, 'output.txt')
File.open(expected_file, 'w') {|file| file << 'expected output' }
# passes
assert_files do
output_file = method_root.filepath(:output, 'output.txt')
File.open(output_file, 'w') {|file| file << 'expected output' }
output_file
end
end
end
See Test::Unit::TestCase and FileTestClass for more information.
Instance Attribute Summary collapse
-
#method_root ⇒ Object
readonly
The test-method-specific Tap::Root which may be used to access test files.
-
#method_tempfiles ⇒ Object
readonly
An array of filepaths setup by method_tempfile; these files are removed by teardown, as they should all be in the output directory.
Class Method Summary collapse
Instance Method Summary collapse
-
#assert_files(options = {}, &block) ⇒ Object
assert_files runs a file-based test that feeds all files from input_dir to the block, then compares the resulting files (which should be relative to output_dir) with all the files in expected_dir.
-
#assert_files_alike(options = {}, &block) ⇒ Object
:yields: input_files.
-
#cleanup_test_directories ⇒ Object
Attempts to remove the method_root.directories, method_root.root, and ctr.root.
-
#ctr ⇒ Object
Convenience method to access the class_test_root.
-
#default_assert_files_options ⇒ Object
The default assert_files options.
-
#make_test_directories ⇒ Object
Creates the method_root.directories.
-
#method_name_str ⇒ Object
Returns method_name as a string (Ruby 1.9 symbolizes method_name).
-
#method_tempfile(filename = method_name_str, &block) ⇒ Object
Generates a temporary filepath formatted like “output_dirfilename.n.ext” where n is a counter that ensures the filepath is unique and non-existant (specificaly n is equal to the number of method_tempfiles generated by the current test, incremented as necessary to achieve a non-existant filepath).
-
#setup ⇒ Object
Sets up method_root and attempts to cleanup any left overs from a previous test (ie by deleting method_root and calling cleanup_test_directories).
-
#teardown ⇒ Object
Deletes the the method_root directory (unless flagged otherwise by an ENV variable) and calls cleanup_test_directories.
Methods included from Assertions
#assert_alike, #assert_output_equal
Methods included from EnvVars
Instance Attribute Details
#method_root ⇒ Object (readonly)
The test-method-specific Tap::Root which may be used to access test files. method_root is a duplicate of ctr reconfigured so that method_root.root is ctr[ method_name.to_sym ]
95 96 97 |
# File 'lib/tap/test/file_test.rb', line 95 def method_root @method_root end |
#method_tempfiles ⇒ Object (readonly)
An array of filepaths setup by method_tempfile; these files are removed by teardown, as they should all be in the output directory.
100 101 102 |
# File 'lib/tap/test/file_test.rb', line 100 def method_tempfiles @method_tempfiles end |
Class Method Details
.included(base) ⇒ Object
64 65 66 67 |
# File 'lib/tap/test/file_test.rb', line 64 def self.included(base) super base.extend FileTestClass end |
Instance Method Details
#assert_files(options = {}, &block) ⇒ Object
assert_files runs a file-based test that feeds all files from input_dir to the block, then compares the resulting files (which should be relative to output_dir) with all the files in expected_dir. Only the files returned by the block are used in the comparison; additional files in the output directory are effectively ignored.
Example
Lets define a test that transforms input files into output files in a trivial way, simply by replacing ‘input’ with ‘output’ in the file.
class FileTestDocTest < Test::Unit::TestCase
acts_as_file_test
def test_sub
assert_files do |input_files|
input_files.collect do |filepath|
input = File.read(filepath)
output_file = method_root.filepath(:output, File.basename(filepath))
File.open(output_file, "w") do |f|
f << input.gsub(/input/, "output")
end
output_file
end
end
end
end
Now say you had some input and expected files for the ‘test_sub’ method:
file_test_doc/test_sub
|- expected
| |- one.txt
| `- two.txt
`- input
|- one.txt
`- two.txt
[input/one.txt]
test input 1
[input/two.txt]
test input 2
[expected/one.txt]
test output 1
[expected/two.txt]
test output 2
When you run the test, the assert_files passes the input files to the block. When the block completes, assert_files compares the output files returned by the block with the files in the expected directory. In this case, the files are equal and the test passes.
Say you changed the content of one of the expected files:
[expected/one.txt]
test flunk 1
Now the test fails because the output files aren’t equal to the expected files. The test will also fail if there are missing or extra files.
Options
A variety of options can be specified to adjust the behavior of assert_files:
:input_dir specify the directory to glob for input files
(default method_root[:input])
:output_dir specify the output directory
(default method_root[:output])
:expected_dir specify the directory to glob for expected files
(default method_root[:expected])
:input_files directly specify the input files for the block
:expected_files directly specify the expected files for comparison
:include_input_directories specifies directories to be included in the
input_files array (by default dirs are excluded)
:include_expected_directories specifies directories to be included in the
expected-output file list comparison
(by default dirs are excluded)
assert_files will fail if :expected_files
was not specified in the options and no files were found in :expected_dir
. This check tries to prevent silent false-positive results when you forget to put expected files in their place.
File References
Sometimes the same files will get used across multiple tests. To allow separate management of test files and prevent duplication, file references can be provided in place of test files. For instance, with a test directory like:
method_root
|- expected
| |- one.txt.ref
| `- two.txt.ref
|- input
| |- one.txt.ref
| `- two.txt.ref
`- ref
|- one.txt
`- two.txt
The input and expected files (all references in this case) can be dereferenced to the ‘ref’ filepaths like so:
assert_files :reference_dir => method_root[:ref] do |input_files|
input_files # => ['method_root/ref/one.txt', 'method_root/ref/two.txt']
input_files.collect do |input_file|
output_file = method_root.filepath(:output, File.basename(input_file)
FileUtils.cp(input_file, output_file)
output_file
end
end
Dereferencing occurs relative to the input_dir/expected_dir configurations; a reference_dir must be specified for dereferencing to occur (see Utils.dereference for more details).
Keeping Outputs
By default FileTest sets teardown to cleans up the output directory. For ease in debugging, ENV variable flags can be specified to keep all output files (KEEP_OUTPUTS) or to keep the output files for just the tests that fail (KEEP_FAILURES). These flags can be specified from the command line if you’re running the tests with rake or rap:
% rake test keep_outputs=true
% rap test keep_failures=true
– TODO:
-
add debugging information to indicate, for instance,
when dereferencing is going on.
313 314 315 316 317 318 319 |
# File 'lib/tap/test/file_test.rb', line 313 def assert_files(={}, &block) # :yields: input_files transform_test(block, ) do |expected_file, output_file| unless FileUtils.cmp(expected_file, output_file) flunk "<#{expected_file}> not equal to\n<#{output_file}>" end end end |
#assert_files_alike(options = {}, &block) ⇒ Object
:yields: input_files
321 322 323 324 325 326 327 |
# File 'lib/tap/test/file_test.rb', line 321 def assert_files_alike(={}, &block) # :yields: input_files transform_test(block, ) do |expected_file, output_file| regexp = RegexpEscape.new(File.read(expected_file)) str = File.read(output_file) assert_alike(regexp, str, "<#{expected_file}> not equal to\n<#{output_file}>") end end |
#cleanup_test_directories ⇒ Object
Attempts to remove the method_root.directories, method_root.root, and ctr.root. Any given directory will not be removed unless empty.
83 84 85 86 87 88 89 90 |
# File 'lib/tap/test/file_test.rb', line 83 def cleanup_test_directories method_root.directories.values.each do |dir| Utils.try_remove_dir(method_root[dir]) end Utils.try_remove_dir(method_root.root) Utils.try_remove_dir(ctr.root) end |
#ctr ⇒ Object
Convenience method to access the class_test_root.
70 71 72 |
# File 'lib/tap/test/file_test.rb', line 70 def ctr self.class.class_test_root end |
#default_assert_files_options ⇒ Object
The default assert_files options
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'lib/tap/test/file_test.rb', line 330 def { :input_dir => method_root[:input], :output_dir => method_root[:output], :expected_dir => method_root[:expected], :input_files => nil, :expected_files => nil, :include_input_directories => false, :include_expected_directories => false, :reference_dir => nil, :reference_extname => '.ref' } end |
#make_test_directories ⇒ Object
Creates the method_root.directories.
75 76 77 78 79 |
# File 'lib/tap/test/file_test.rb', line 75 def make_test_directories method_root.directories.values.each do |dir| FileUtils.mkdir_p( method_root[dir] ) end end |
#method_name_str ⇒ Object
Returns method_name as a string (Ruby 1.9 symbolizes method_name)
145 146 147 |
# File 'lib/tap/test/file_test.rb', line 145 def method_name_str method_name.to_s end |
#method_tempfile(filename = method_name_str, &block) ⇒ Object
Generates a temporary filepath formatted like “output_dirfilename.n.ext” where n is a counter that ensures the filepath is unique and non-existant (specificaly n is equal to the number of method_tempfiles generated by the current test, incremented as necessary to achieve a non-existant filepath).
Unlike Tempfile, method_tempfile does not create the filepath unless a block is given, in which case an open File will be passed to the block. In addition, method_tempfiles are only cleaned up indirectly when the output directory is removed by teardown; this is both convenient for testing (when you may want a the file to persist, so you can debug it) and less enforcing than Tempfile.
Notes:
-
by default filename is the calling method
-
the extension is chomped off the end of the filename
-
the directory for the file will be created if it does not exist
-
like all files in the output directory, tempfiles will be deleted by the default
teardown
method
168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/tap/test/file_test.rb', line 168 def method_tempfile(filename=method_name_str, &block) ext = File.extname(filename) basename = filename.chomp(ext) path = next_indexed_path(method_root.filepath(:output, basename), method_tempfiles.length, ext) dirname = File.dirname(path) method_tempfiles << path FileUtils.mkdir_p(dirname) unless File.exists?(dirname) File.open(path, "w", &block) if block_given? path end |
#setup ⇒ Object
Sets up method_root and attempts to cleanup any left overs from a previous test (ie by deleting method_root and calling cleanup_test_directories). Be sure to call super when overriding this method.
106 107 108 109 110 111 112 113 |
# File 'lib/tap/test/file_test.rb', line 106 def setup super @method_root = ctr.dup.reconfigure(:root => ctr[method_name.to_sym]) @method_tempfiles = [] Utils.clear_dir(method_root[:output]) cleanup_test_directories end |
#teardown ⇒ Object
Deletes the the method_root directory (unless flagged otherwise by an ENV variable) and calls cleanup_test_directories. To keep all output directories, or to only keep output directories for failing tests, set the ‘KEEP_OUTPUTS’ or ‘KEEP_FAILURES’ ENV variables:
% rap test KEEP_OUTPUTS=true
% rap test KEEP_FAILURES=true
Be sure to call super when overriding this method.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/tap/test/file_test.rb', line 125 def teardown # check that method_root still exists (nil may # indicate setup was overridden without super) unless method_root raise "teardown failure: method_root is nil" end # clear out the output folder if it exists, unless flagged otherwise unless env("KEEP_OUTPUTS") || (!passed? && env("KEEP_FAILURES")) begin Utils.clear_dir(method_root[:output]) rescue raise("teardown failure: could not remove output files (#{$!.})") end end cleanup_test_directories end |