bahuvrihi-tap 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +69 -0
- data/MIT-LICENSE +21 -0
- data/README +119 -0
- data/bin/tap +114 -0
- data/cmd/console.rb +42 -0
- data/cmd/destroy.rb +16 -0
- data/cmd/generate.rb +16 -0
- data/cmd/run.rb +126 -0
- data/doc/Class Reference +362 -0
- data/doc/Command Reference +153 -0
- data/doc/Tutorial +237 -0
- data/lib/tap.rb +32 -0
- data/lib/tap/app.rb +720 -0
- data/lib/tap/constants.rb +8 -0
- data/lib/tap/env.rb +640 -0
- data/lib/tap/file_task.rb +547 -0
- data/lib/tap/generator/base.rb +109 -0
- data/lib/tap/generator/destroy.rb +37 -0
- data/lib/tap/generator/generate.rb +61 -0
- data/lib/tap/generator/generators/command/command_generator.rb +21 -0
- data/lib/tap/generator/generators/command/templates/command.erb +32 -0
- data/lib/tap/generator/generators/config/config_generator.rb +26 -0
- data/lib/tap/generator/generators/config/templates/doc.erb +12 -0
- data/lib/tap/generator/generators/config/templates/nodoc.erb +8 -0
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +27 -0
- data/lib/tap/generator/generators/file_task/templates/file.txt +11 -0
- data/lib/tap/generator/generators/file_task/templates/result.yml +6 -0
- data/lib/tap/generator/generators/file_task/templates/task.erb +33 -0
- data/lib/tap/generator/generators/file_task/templates/test.erb +29 -0
- data/lib/tap/generator/generators/root/root_generator.rb +55 -0
- data/lib/tap/generator/generators/root/templates/Rakefile +86 -0
- data/lib/tap/generator/generators/root/templates/gemspec +27 -0
- data/lib/tap/generator/generators/root/templates/tapfile +8 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +3 -0
- data/lib/tap/generator/generators/root/templates/test/tap_test_suite.rb +5 -0
- data/lib/tap/generator/generators/root/templates/test/tapfile_test.rb +15 -0
- data/lib/tap/generator/generators/task/task_generator.rb +27 -0
- data/lib/tap/generator/generators/task/templates/task.erb +14 -0
- data/lib/tap/generator/generators/task/templates/test.erb +21 -0
- data/lib/tap/generator/manifest.rb +14 -0
- data/lib/tap/patches/rake/rake_test_loader.rb +8 -0
- data/lib/tap/patches/rake/testtask.rb +55 -0
- data/lib/tap/patches/ruby19/backtrace_filter.rb +51 -0
- data/lib/tap/patches/ruby19/parsedate.rb +16 -0
- data/lib/tap/root.rb +581 -0
- data/lib/tap/support/aggregator.rb +55 -0
- data/lib/tap/support/assignments.rb +172 -0
- data/lib/tap/support/audit.rb +418 -0
- data/lib/tap/support/batchable.rb +47 -0
- data/lib/tap/support/batchable_class.rb +107 -0
- data/lib/tap/support/class_configuration.rb +194 -0
- data/lib/tap/support/command_line.rb +98 -0
- data/lib/tap/support/comment.rb +270 -0
- data/lib/tap/support/configurable.rb +114 -0
- data/lib/tap/support/configurable_class.rb +296 -0
- data/lib/tap/support/configuration.rb +122 -0
- data/lib/tap/support/constant.rb +70 -0
- data/lib/tap/support/constant_utils.rb +127 -0
- data/lib/tap/support/declarations.rb +111 -0
- data/lib/tap/support/executable.rb +111 -0
- data/lib/tap/support/executable_queue.rb +82 -0
- data/lib/tap/support/framework.rb +71 -0
- data/lib/tap/support/framework_class.rb +199 -0
- data/lib/tap/support/instance_configuration.rb +147 -0
- data/lib/tap/support/lazydoc.rb +428 -0
- data/lib/tap/support/manifest.rb +89 -0
- data/lib/tap/support/run_error.rb +39 -0
- data/lib/tap/support/shell_utils.rb +71 -0
- data/lib/tap/support/summary.rb +30 -0
- data/lib/tap/support/tdoc.rb +404 -0
- data/lib/tap/support/tdoc/tdoc_html_generator.rb +38 -0
- data/lib/tap/support/tdoc/tdoc_html_template.rb +42 -0
- data/lib/tap/support/templater.rb +180 -0
- data/lib/tap/support/validation.rb +410 -0
- data/lib/tap/support/versions.rb +97 -0
- data/lib/tap/task.rb +259 -0
- data/lib/tap/tasks/dump.rb +56 -0
- data/lib/tap/tasks/rake.rb +93 -0
- data/lib/tap/test.rb +37 -0
- data/lib/tap/test/env_vars.rb +29 -0
- data/lib/tap/test/file_methods.rb +377 -0
- data/lib/tap/test/script_methods.rb +144 -0
- data/lib/tap/test/subset_methods.rb +420 -0
- data/lib/tap/test/tap_methods.rb +237 -0
- data/lib/tap/workflow.rb +187 -0
- metadata +145 -0
data/lib/tap/test.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'tap/test/tap_methods'
|
2
|
+
|
3
|
+
module Test # :nodoc:
|
4
|
+
module Unit # :nodoc:
|
5
|
+
|
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
|
+
#
|
19
|
+
#--
|
20
|
+
#See the TestTutorial for more information.
|
21
|
+
class TestCase
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Tap
|
27
|
+
|
28
|
+
# Modules facilitating testing. TapMethods are specific to
|
29
|
+
# Tap, but SubsetMethods and FileMethods are more general in
|
30
|
+
# their utility.
|
31
|
+
module Test
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Tap
|
2
|
+
module Test
|
3
|
+
|
4
|
+
# Provides for case-insensitive access to the ENV variables
|
5
|
+
module EnvVars
|
6
|
+
|
7
|
+
# Access to the case-insensitive ENV variables. Raises an error
|
8
|
+
# if multiple case-insensitive values are defined in ENV.
|
9
|
+
def env(type)
|
10
|
+
type = type.downcase
|
11
|
+
|
12
|
+
# ruby 1.9 returns a hash instead of an array
|
13
|
+
selected = ENV.select {|key, value| key.downcase == type}.to_a
|
14
|
+
|
15
|
+
case selected.length
|
16
|
+
when 0 then nil
|
17
|
+
when 1 then selected[0][1]
|
18
|
+
else
|
19
|
+
raise "Multiple env values for '#{type}'"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns true if the env_var(var) is set and matches /^true$/i
|
24
|
+
def env_true?(var)
|
25
|
+
env(var) && env(var) =~ /^true$/i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,377 @@
|
|
1
|
+
require 'tap/root'
|
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
|
55
|
+
|
56
|
+
module Tap
|
57
|
+
module Test
|
58
|
+
|
59
|
+
|
60
|
+
# FileMethods sets up a TestCase with methods for accessing and utilizing
|
61
|
+
# test-specific files and directories. Each class that acts_as_file_test
|
62
|
+
# is set up with a Tap::Root structure (trs) that mediates the creation of
|
63
|
+
# test method filepaths.
|
64
|
+
#
|
65
|
+
# class FileMethodsDocTest < Test::Unit::TestCase
|
66
|
+
# acts_as_file_test
|
67
|
+
#
|
68
|
+
# def test_something
|
69
|
+
# # dir = File.expand_path( File.dirname(__FILE__) )
|
70
|
+
# trs.root # => dir + "/file_methods_doc",
|
71
|
+
# method_root # => dir + "/file_methods_doc/test_something",
|
72
|
+
# method_dir(:input) # => dir + "/file_methods_doc/test_something/input"
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# === assert_files
|
77
|
+
#
|
78
|
+
# FileMethods is specifically designed for tests that transform a set of input
|
79
|
+
# files into output files. For this type of test, input and expected files can
|
80
|
+
# placed into their respective directories then used within the context of
|
81
|
+
# assert_files to ensure the output files are equal to the expected files.
|
82
|
+
#
|
83
|
+
# For example, lets define a test that transforms input files into output files
|
84
|
+
# in a trivial way, simply by replacing 'input' with 'output' in the file.
|
85
|
+
#
|
86
|
+
# class FileMethodsDocTest < Test::Unit::TestCase
|
87
|
+
# acts_as_file_test
|
88
|
+
#
|
89
|
+
# def test_sub
|
90
|
+
# assert_files do |input_files|
|
91
|
+
# input_files.collect do |filepath|
|
92
|
+
# input = File.read(filepath)
|
93
|
+
# output_file = method_filepath(:output, File.basename(filepath))
|
94
|
+
#
|
95
|
+
# File.open(output_file, "w") do |f|
|
96
|
+
# f << input.gsub(/input/, "output")
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# output_file
|
100
|
+
# end
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
#
|
105
|
+
# Now say you had some input and expected files for the 'test_sub' method:
|
106
|
+
#
|
107
|
+
# [file_methods_doc/test_sub/input/one.txt]
|
108
|
+
# test input 1
|
109
|
+
#
|
110
|
+
# [file_methods_doc/test_sub/input/two.txt]
|
111
|
+
# test input 2
|
112
|
+
#
|
113
|
+
# [file_methods_doc/test_sub/expected/one.txt]
|
114
|
+
# test output 1
|
115
|
+
#
|
116
|
+
# [file_methods_doc/test_sub/expected/two.txt]
|
117
|
+
# test output 2
|
118
|
+
#
|
119
|
+
# When you run the FileMethodsDocTest test, the test_sub test will pass
|
120
|
+
# the input files to the assert_files block. Then assert_files compares
|
121
|
+
# the returned filepaths with the expected files translated from the
|
122
|
+
# expected directory to the output directory. In this case, the files
|
123
|
+
# are equal and the test passes.
|
124
|
+
#
|
125
|
+
# The test fails if the returned files aren't equal to the expected files,
|
126
|
+
# either because there are missing or extra files, or if the file contents
|
127
|
+
# are different.
|
128
|
+
#
|
129
|
+
# When the test completes, the teardown method cleans up the output directory.
|
130
|
+
# For ease in debugging, ENV variable flags can be specified to keep all
|
131
|
+
# output files (KEEP_OUTPUTS) or to keep the output files for just the tests
|
132
|
+
# that fail (KEEP_FAILURES). These flags can be specified from the command
|
133
|
+
# line if you're running the tests with rake or tap:
|
134
|
+
#
|
135
|
+
# % rake test keep_outputs=true
|
136
|
+
# % tap run test keep_failures=true
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# === Class Methods
|
140
|
+
#
|
141
|
+
# See {Test::Unit::TestCase}[link:classes/Test/Unit/TestCase.html] for documentation of the class methods added by FileMethods.
|
142
|
+
module FileMethods
|
143
|
+
include Tap::Test::EnvVars
|
144
|
+
|
145
|
+
# Convenience accessor for the test root structure
|
146
|
+
def trs
|
147
|
+
self.class.trs
|
148
|
+
end
|
149
|
+
|
150
|
+
# Creates the trs.directories, specific to the method calling make_test_directories
|
151
|
+
def make_test_directories
|
152
|
+
trs.directories.values.each do |dir|
|
153
|
+
FileUtils.mkdir_p( File.join(trs.root, method_name_str, dir) )
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
attr_reader :method_tempfiles
|
158
|
+
|
159
|
+
# Setup deletes the the output directory if it exists, and tries to remove the
|
160
|
+
# method root directory so the directory structure is reset before running the
|
161
|
+
# test, even if outputs were left over from previous tests.
|
162
|
+
def setup
|
163
|
+
super
|
164
|
+
@method_tempfiles = []
|
165
|
+
clear_method_dir(:output)
|
166
|
+
try_remove_dir(method_root)
|
167
|
+
end
|
168
|
+
|
169
|
+
# Teardown deletes the the output directories unless flagged otherwise. Note
|
170
|
+
# that teardown also checks the environment variables for flags. To keep all outputs
|
171
|
+
# (or failures) for all tests, flag keep outputs from the command line like:
|
172
|
+
#
|
173
|
+
# % tap run test KEEP_OUTPUTS=true
|
174
|
+
# % tap run test KEEP_FAILURES=true
|
175
|
+
def teardown
|
176
|
+
# clear out the output folder if it exists, unless flagged otherwise
|
177
|
+
unless env("KEEP_OUTPUTS") || (!@test_passed && env("KEEP_FAILURES"))
|
178
|
+
begin
|
179
|
+
clear_method_dir(:output)
|
180
|
+
rescue
|
181
|
+
raise("teardown failure: could not remove output files")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
try_remove_dir(method_root)
|
186
|
+
try_remove_dir(trs.root)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns method_name as a string (Ruby 1.9 symbolizes method_name)
|
190
|
+
def method_name_str
|
191
|
+
method_name.to_s
|
192
|
+
end
|
193
|
+
|
194
|
+
# The method_root directory is defined as trs.filepath(method_name)
|
195
|
+
def method_root(method=method_name_str)
|
196
|
+
trs.filepath(method)
|
197
|
+
end
|
198
|
+
|
199
|
+
# The method directory is defined as 'dir/method', where method is the calling method
|
200
|
+
# by default. method_dir returns the method directory if it exists, otherwise it returns
|
201
|
+
# trs[dir].
|
202
|
+
def method_dir(dir, method=method_name_str)
|
203
|
+
File.join(method_root(method), trs.directories[dir] || dir.to_s)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Returns a glob of files matching the input pattern, underneath the method directory
|
207
|
+
# if it exists, otherwise the <tt>trs[dir]</tt> directory.
|
208
|
+
def method_glob(dir, *patterns)
|
209
|
+
dir = trs.relative_filepath(:root, method_dir(dir))
|
210
|
+
trs.glob(dir, *patterns)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Returns a filepath constructed from the method directory if it exists,
|
214
|
+
# otherwise the filepath will be constructed from <tt>trs[dir]</tt>.
|
215
|
+
def method_filepath(dir, *filenames)
|
216
|
+
File.join(method_dir(dir), *filenames)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Removes the method directory from the input filepath, returning the resuting filename.
|
220
|
+
# If the method directory does not exist, <tt>trs[dir]</tt> will be removed.
|
221
|
+
def method_relative_filepath(dir, filepath)
|
222
|
+
dir = trs.relative_filepath(:root, method_dir(dir))
|
223
|
+
trs.relative_filepath(dir, filepath)
|
224
|
+
end
|
225
|
+
|
226
|
+
# Returns an output file corresponding to the input file, translated from the
|
227
|
+
# input directory to the output directory.
|
228
|
+
#
|
229
|
+
# If the input method directory exists, it will be removed from the filepath.
|
230
|
+
# If the output method directory exists, it will be inserted in the filepath.
|
231
|
+
def method_translate(filepath, input_dir, output_dir)
|
232
|
+
input_dir = trs.relative_filepath(:root, method_dir(input_dir))
|
233
|
+
output_dir = trs.relative_filepath(:root, method_dir(output_dir))
|
234
|
+
trs.translate(filepath, input_dir, output_dir)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Attempts to recursively remove the specified method directory and all
|
238
|
+
# files within it. Raises an error if the removal does not succeed.
|
239
|
+
def clear_method_dir(dir)
|
240
|
+
# clear out the folder if it exists
|
241
|
+
dir_path = method_dir(dir, method_name_str)
|
242
|
+
FileUtils.rm_r(dir_path) if File.exists?(dir_path)
|
243
|
+
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
|
+
|
257
|
+
# Generates a temporary filepath formatted like "output_dir\filename.pid.n.ext" where n
|
258
|
+
# is a counter that will be incremented from until a non-existant filepath is achieved.
|
259
|
+
#
|
260
|
+
# Notes:
|
261
|
+
# - By default filename is the calling method
|
262
|
+
# - The extension is chomped off the end of the filename
|
263
|
+
# - If the directory for the filepath does not exist, the directory will be created
|
264
|
+
# - Like all files in the output directory, tempfiles will be deleted by the default
|
265
|
+
# +teardown+ method
|
266
|
+
def method_tempfile(filename=method_name_str, &block)
|
267
|
+
ext = File.extname(filename)
|
268
|
+
basename = filename.chomp(ext)
|
269
|
+
filepath = method_filepath(:output, sprintf('%s%d.%d%s', basename, $$, method_tempfiles.length, ext))
|
270
|
+
method_tempfiles << filepath
|
271
|
+
|
272
|
+
dirname = File.dirname(filepath)
|
273
|
+
FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
|
274
|
+
if block_given?
|
275
|
+
File.open(filepath, "w", &block)
|
276
|
+
end
|
277
|
+
filepath
|
278
|
+
end
|
279
|
+
|
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)
|
301
|
+
# 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.
|
305
|
+
#
|
306
|
+
# A variety of options can be specified to adjust the behavior:
|
307
|
+
#
|
308
|
+
# :input_files specify the input files to pass to the block
|
309
|
+
# :expected_files specify the expected files used in comparison
|
310
|
+
# :include_input_directories specifies directories to be included in the
|
311
|
+
# input_files array (by default dirs are excluded)
|
312
|
+
# :include_expected_directories specifies directories to be included in the
|
313
|
+
# expected-output file list comparison (by default
|
314
|
+
# dirs are excluded, note that naturally only files
|
315
|
+
# have their actual content compared)
|
316
|
+
#
|
317
|
+
# Option keys should be symbols. assert_files will fail if :expected_files was
|
318
|
+
# not specified in the options and no files were found in method_dir(:expected).
|
319
|
+
# This tries to prevent silent false-positive results when you forget to put
|
320
|
+
# expected files in their place.
|
321
|
+
def assert_files(options={}) # :yields: input_files
|
322
|
+
make_test_directories
|
323
|
+
|
324
|
+
options = {
|
325
|
+
:input_files => nil,
|
326
|
+
:expected_files => nil,
|
327
|
+
|
328
|
+
:include_input_directories => false,
|
329
|
+
:include_expected_directories => false
|
330
|
+
}.merge(options)
|
331
|
+
|
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
|
341
|
+
|
342
|
+
unless options["include_#{key}_directories".to_sym]
|
343
|
+
files.delete_if {|file| File.directory?(file)}
|
344
|
+
end
|
345
|
+
|
346
|
+
files
|
347
|
+
end
|
348
|
+
|
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
|
358
|
+
|
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}>"
|
370
|
+
end
|
371
|
+
end
|
372
|
+
flunk "File compare failed:\n" + errors.join("\n") unless errors.empty?
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'tap/test/file_methods'
|
3
|
+
require 'tap/test/subset_methods'
|
4
|
+
#require 'tap/support/shell_utils'
|
5
|
+
|
6
|
+
module Test # :nodoc:
|
7
|
+
module Unit # :nodoc:
|
8
|
+
class TestCase
|
9
|
+
class << self
|
10
|
+
|
11
|
+
def acts_as_script_test(options={})
|
12
|
+
options = options.inject({:root => file_test_root}) do |hash, (key, value)|
|
13
|
+
hash[key.to_sym || key] = value
|
14
|
+
hash
|
15
|
+
end
|
16
|
+
acts_as_file_test(options)
|
17
|
+
include Tap::Test::SubsetMethods
|
18
|
+
include Tap::Test::ScriptMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Tap
|
27
|
+
module Test
|
28
|
+
|
29
|
+
module ScriptMethods
|
30
|
+
class CommandTest
|
31
|
+
attr_accessor :command_path
|
32
|
+
attr_reader :commands
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
@command_path = nil
|
36
|
+
@commands = []
|
37
|
+
end
|
38
|
+
|
39
|
+
def check(argstr, msg=nil, expected=nil, &block)
|
40
|
+
commands << ["#{command_path}#{argstr}", msg, expected, block]
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_cmd(cmd, msg=nil, expected=nil, &block)
|
44
|
+
commands << [cmd, msg, expected, block]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
include Tap::Support::ShellUtils
|
49
|
+
|
50
|
+
def assert_output_equal(a, b, cmd, msg)
|
51
|
+
a = a[1..-1] if a[0] == ?\n
|
52
|
+
if a == b
|
53
|
+
assert true
|
54
|
+
else
|
55
|
+
flunk %Q{
|
56
|
+
#{msg}
|
57
|
+
% #{cmd}
|
58
|
+
==================== expected output ====================
|
59
|
+
#{a.gsub(/\t/, "\\t").gsub(/\r\n/, "\\r\\n\n").gsub(/\n/, "\\n\n")}
|
60
|
+
======================== but was ========================
|
61
|
+
#{b.gsub(/\t/, "\\t").gsub(/\r\n/, "\\r\\n\n").gsub(/\n/, "\\n\n")}
|
62
|
+
=========================================================
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def assert_alike(a, b, cmd, msg)
|
68
|
+
if b =~ a
|
69
|
+
assert true
|
70
|
+
else
|
71
|
+
flunk %Q{
|
72
|
+
#{msg}
|
73
|
+
% #{cmd}
|
74
|
+
================= expected output like ==================
|
75
|
+
#{a}
|
76
|
+
======================== but was ========================
|
77
|
+
#{b.gsub(/\t/, "\\t").gsub(/\r\n/, "\\r\\n\n").gsub(/\n/, "\\n\n")}
|
78
|
+
=========================================================
|
79
|
+
}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def script_test(test_dir=method_dir(:output))
|
84
|
+
subset_test("SCRIPT", "s") do
|
85
|
+
test = CommandTest.new
|
86
|
+
yield(test)
|
87
|
+
|
88
|
+
current_dir = Dir.pwd
|
89
|
+
current_argv = ARGV.dup
|
90
|
+
begin
|
91
|
+
ARGV.clear
|
92
|
+
make_test_directories
|
93
|
+
Dir.chdir(test_dir)
|
94
|
+
|
95
|
+
puts "\n# == #{method_name}"
|
96
|
+
|
97
|
+
test.commands.each do |cmd, msg, expected, block|
|
98
|
+
start = Time.now
|
99
|
+
result = capture_sh(cmd) {|ok, status, tempfile_path| }
|
100
|
+
elapsed = Time.now - start
|
101
|
+
|
102
|
+
case expected
|
103
|
+
when String
|
104
|
+
assert_output_equal(expected, result, cmd, msg)
|
105
|
+
when Regexp
|
106
|
+
assert_alike(expected, result, cmd, msg)
|
107
|
+
end
|
108
|
+
|
109
|
+
if block
|
110
|
+
block.call(result)
|
111
|
+
end
|
112
|
+
|
113
|
+
if env('stepwise') || (expected == nil && block == nil)
|
114
|
+
print %Q{
|
115
|
+
------------------------------------
|
116
|
+
%s
|
117
|
+
> %s
|
118
|
+
%s
|
119
|
+
Time Elapsed: %.3fs} % [msg, cmd, result, elapsed]
|
120
|
+
|
121
|
+
if env('stepwise')
|
122
|
+
print "\nContinue? (y/n): "
|
123
|
+
break if gets.strip =~ /^no?$/i
|
124
|
+
end
|
125
|
+
else
|
126
|
+
puts "%.3fs : %s" % [elapsed, msg]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
ensure
|
130
|
+
Dir.chdir(current_dir)
|
131
|
+
ARGV.clear
|
132
|
+
ARGV.concat(current_argv)
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
|