tap 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Basic Overview +151 -0
- data/Command Reference +99 -0
- data/History +24 -0
- data/MIT-LICENSE +1 -1
- data/README +29 -57
- data/Rakefile +30 -37
- data/Tutorial +243 -191
- data/bin/tap +66 -35
- data/lib/tap.rb +47 -29
- data/lib/tap/app.rb +700 -342
- data/lib/tap/{script → cmd}/console.rb +0 -0
- data/lib/tap/{script → cmd}/destroy.rb +0 -0
- data/lib/tap/{script → cmd}/generate.rb +0 -0
- data/lib/tap/cmd/run.rb +156 -0
- data/lib/tap/constants.rb +4 -0
- data/lib/tap/dump.rb +57 -0
- data/lib/tap/env.rb +316 -0
- data/lib/tap/file_task.rb +106 -109
- data/lib/tap/generator.rb +4 -1
- data/lib/tap/generator/generators/command/USAGE +6 -0
- data/lib/tap/generator/generators/command/command_generator.rb +17 -0
- data/lib/tap/generator/generators/{script/templates/script.erb → command/templates/command.erb} +10 -10
- data/lib/tap/generator/generators/config/USAGE +21 -0
- data/lib/tap/generator/generators/config/config_generator.rb +17 -7
- data/lib/tap/generator/generators/file_task/USAGE +3 -0
- data/lib/tap/generator/generators/file_task/file_task_generator.rb +16 -0
- data/lib/tap/generator/generators/file_task/templates/file.txt +2 -0
- data/lib/tap/generator/generators/file_task/templates/file.yml +3 -0
- data/lib/tap/generator/generators/file_task/templates/task.erb +26 -20
- data/lib/tap/generator/generators/file_task/templates/test.erb +20 -10
- data/lib/tap/generator/generators/generator/generator_generator.rb +1 -1
- data/lib/tap/generator/generators/generator/templates/generator.erb +21 -12
- data/lib/tap/generator/generators/root/templates/Rakefile +33 -24
- data/lib/tap/generator/generators/root/templates/tap.yml +28 -31
- data/lib/tap/generator/generators/root/templates/test/tap_test_helper.rb +1 -0
- data/lib/tap/generator/generators/task/USAGE +3 -0
- data/lib/tap/generator/generators/task/task_generator.rb +18 -5
- data/lib/tap/generator/generators/task/templates/task.erb +7 -12
- data/lib/tap/generator/generators/task/templates/test.erb +10 -11
- data/lib/tap/generator/generators/workflow/templates/task.erb +1 -1
- data/lib/tap/generator/generators/workflow/templates/test.erb +1 -1
- 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 +172 -67
- data/lib/tap/script.rb +70 -336
- data/lib/tap/support/aggregator.rb +55 -0
- data/lib/tap/support/audit.rb +281 -280
- data/lib/tap/support/batchable.rb +59 -0
- data/lib/tap/support/class_configuration.rb +279 -0
- data/lib/tap/support/configurable.rb +92 -0
- data/lib/tap/support/configurable_methods.rb +296 -0
- data/lib/tap/support/executable.rb +98 -0
- data/lib/tap/support/executable_queue.rb +82 -0
- data/lib/tap/support/logger.rb +9 -15
- data/lib/tap/support/rake.rb +43 -54
- data/lib/tap/support/run_error.rb +32 -13
- data/lib/tap/support/shell_utils.rb +47 -0
- data/lib/tap/support/tdoc.rb +9 -8
- data/lib/tap/support/tdoc/config_attr.rb +40 -16
- data/lib/tap/support/validation.rb +77 -0
- data/lib/tap/support/versions.rb +36 -36
- data/lib/tap/task.rb +276 -482
- data/lib/tap/test.rb +20 -261
- data/lib/tap/test/env_vars.rb +7 -5
- data/lib/tap/test/file_methods.rb +126 -121
- data/lib/tap/test/subset_methods.rb +86 -45
- data/lib/tap/test/tap_methods.rb +271 -0
- data/lib/tap/workflow.rb +174 -46
- data/test/app/config/another/task.yml +1 -0
- data/test/app/config/erb.yml +2 -1
- data/test/app/config/some/task.yml +1 -0
- data/test/app/config/template.yml +2 -6
- data/test/app_test.rb +1241 -1008
- data/test/env/test_configure/recurse_a.yml +2 -0
- data/test/env/test_configure/recurse_b.yml +2 -0
- data/test/env/test_configure/tap.yml +23 -0
- data/test/env/test_load_env_config/dir/tap.yml +3 -0
- data/test/env/test_load_env_config/recurse_a.yml +2 -0
- data/test/env/test_load_env_config/recurse_b.yml +2 -0
- data/test/env/test_load_env_config/tap.yml +3 -0
- data/test/env_test.rb +198 -0
- data/test/file_task_test.rb +70 -53
- data/{lib/tap/generator/generators/package/USAGE → test/root/file.txt} +0 -0
- data/test/root_test.rb +621 -454
- data/test/script_test.rb +38 -174
- data/test/support/aggregator_test.rb +99 -0
- data/test/support/audit_test.rb +409 -416
- data/test/support/batchable_test.rb +74 -0
- data/test/support/{task_configuration_test.rb → class_configuration_test.rb} +106 -47
- data/test/{task/config/overriding.yml → support/configurable/config/configured.yml} +0 -0
- data/test/support/configurable_test.rb +295 -0
- data/test/support/executable_queue_test.rb +103 -0
- data/test/support/executable_test.rb +38 -0
- data/test/support/logger_test.rb +17 -17
- data/test/support/rake_test.rb +4 -2
- data/test/support/shell_utils_test.rb +24 -0
- data/test/support/tdoc_test.rb +265 -258
- data/test/support/validation_test.rb +54 -0
- data/test/support/versions_test.rb +38 -38
- data/test/tap_test_helper.rb +19 -5
- data/test/tap_test_suite.rb +5 -2
- data/test/task_base_test.rb +13 -104
- data/test/task_syntax_test.rb +300 -0
- data/test/task_test.rb +258 -381
- data/test/test/env_vars_test.rb +40 -40
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/one.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/expected/two.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/one.txt +0 -0
- data/test/test/file_methods/{test_assert_output_files_equal → test_assert_files}/input/two.txt +0 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/one.txt +0 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_can_have_no_expected_files_if_specified}/input/two.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/expected/one.txt +1 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_different_content}/expected/two.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_different_content/input/two.txt +1 -0
- data/test/test/{test_file_task_test → file_methods/test_assert_files_fails_for_missing_expected_file}/expected/one.txt +0 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_expected_file/input/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/expected/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_missing_output_file/input/two.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/one.txt +1 -0
- data/test/test/file_methods/test_assert_files_fails_for_no_expected_files/input/two.txt +1 -0
- data/test/test/file_methods_doc/test_sub/expected/one.txt +1 -0
- data/test/test/file_methods_doc/test_sub/expected/two.txt +1 -0
- data/test/test/file_methods_doc/test_sub/input/one.txt +1 -0
- data/test/test/file_methods_doc/test_sub/input/two.txt +1 -0
- data/test/test/file_methods_doc_test.rb +29 -0
- data/test/test/file_methods_test.rb +214 -143
- data/test/test/subset_methods_test.rb +111 -115
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/a.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/expected/task/name/b.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/a.txt +0 -0
- data/test/test/{test_assert_expected_result_files → tap_methods/test_assert_files}/input/b.txt +0 -0
- data/test/test/tap_methods_test.rb +399 -0
- data/test/workflow_test.rb +101 -91
- metadata +86 -70
- data/lib/tap/generator/generators/package/package_generator.rb +0 -38
- data/lib/tap/generator/generators/package/templates/package.erb +0 -186
- data/lib/tap/generator/generators/script/USAGE +0 -0
- data/lib/tap/generator/generators/script/script_generator.rb +0 -17
- data/lib/tap/script/run.rb +0 -154
- data/lib/tap/support/batch_queue.rb +0 -162
- data/lib/tap/support/combinator.rb +0 -114
- data/lib/tap/support/task_configuration.rb +0 -169
- data/lib/tap/support/template.rb +0 -81
- data/lib/tap/support/templater.rb +0 -155
- data/lib/tap/version.rb +0 -4
- data/test/app/config/addition_template.yml +0 -6
- data/test/app_class_test.rb +0 -33
- data/test/check/binding_eval.rb +0 -23
- data/test/check/define_method_check.rb +0 -22
- data/test/check/dependencies_check.rb +0 -175
- data/test/check/inheritance_check.rb +0 -22
- data/test/support/batch_queue_test.rb +0 -320
- data/test/support/combinator_test.rb +0 -249
- data/test/support/template_test.rb +0 -122
- data/test/support/templater/erb.txt +0 -2
- data/test/support/templater/erb.yml +0 -2
- data/test/support/templater/somefile.txt +0 -2
- data/test/support/templater_test.rb +0 -192
- data/test/task/config/template.yml +0 -4
- data/test/task_class_test.rb +0 -170
- data/test/task_execute_test.rb +0 -262
- data/test/test/file_methods/test_assert_expected/expected/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/expected/folder/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/input/file.txt +0 -1
- data/test/test/file_methods/test_assert_expected/input/folder/file.txt +0 -1
- data/test/test/file_methods/test_assert_files_exist/input/input_1.txt +0 -0
- data/test/test/file_methods/test_assert_files_exist/input/input_2.txt +0 -0
- data/test/test/file_methods/test_file_compare/expected/output_1.txt +0 -3
- data/test/test/file_methods/test_file_compare/expected/output_2.txt +0 -1
- data/test/test/file_methods/test_file_compare/input/input_1.txt +0 -3
- data/test/test/file_methods/test_file_compare/input/input_2.txt +0 -3
- data/test/test/file_methods/test_infer_glob/expected/file.yml +0 -0
- data/test/test/file_methods/test_infer_glob/expected/file_1.txt +0 -0
- data/test/test/file_methods/test_infer_glob/expected/file_2.txt +0 -0
- data/test/test/file_methods/test_yml_compare/expected/output_1.yml +0 -6
- data/test/test/file_methods/test_yml_compare/expected/output_2.yml +0 -6
- data/test/test/file_methods/test_yml_compare/input/input_1.yml +0 -4
- data/test/test/file_methods/test_yml_compare/input/input_2.yml +0 -4
- data/test/test_test.rb +0 -373
data/lib/tap/test.rb
CHANGED
@@ -1,275 +1,34 @@
|
|
1
|
-
require 'test/
|
2
|
-
require 'tap/test/file_methods'
|
3
|
-
require 'tap/test/subset_methods'
|
1
|
+
require 'tap/test/tap_methods'
|
4
2
|
|
5
3
|
module Test # :nodoc:
|
6
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.
|
7
21
|
class TestCase
|
8
|
-
class << self
|
9
|
-
# Causes a unit test to act as a tap test -- resulting in the following:
|
10
|
-
# - setup using acts_as_file_test
|
11
|
-
# - inclusion of Tap::Test::SubsetMethods
|
12
|
-
# - inclusion of Tap::Test::InstanceMethods
|
13
|
-
#
|
14
|
-
# Note: Unless otherwise specified, +acts_as_tap_test+ infers a root directory
|
15
|
-
# based on the calling file. Be sure to specify the root directory explicitly
|
16
|
-
# if you call acts_as_file_test from a file that is NOT meant to be test file.
|
17
|
-
def acts_as_tap_test(options={})
|
18
|
-
options = {:root => file_test_root}.merge(options.symbolize_keys)
|
19
|
-
acts_as_file_test(options)
|
20
|
-
|
21
|
-
include Tap::Test::SubsetMethods
|
22
|
-
include Tap::Test::InstanceMethods
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|
29
25
|
|
30
26
|
module Tap
|
31
27
|
|
32
|
-
#
|
28
|
+
# Modules facilitating testing. Tap::Test::TapMethods are specific to
|
29
|
+
# Tap, but the other modules Tap::Test::SubsetMethods and
|
30
|
+
# Tap::Test::FileMethods are more general in their utility.
|
33
31
|
module Test
|
34
|
-
|
35
|
-
# Used during check_audit to hold the sources and values of an audit
|
36
|
-
# in the correct order. Oriented so that the next value to be checked
|
37
|
-
# is at the top of the stack.
|
38
|
-
class AuditStack # :nodoc:
|
39
|
-
attr_reader :test
|
40
|
-
|
41
|
-
def initialize(test)
|
42
|
-
@test = test
|
43
|
-
@stack = []
|
44
|
-
end
|
45
|
-
|
46
|
-
def load_audit(values)
|
47
|
-
[values._sources, values._values].transpose.reverse_each do |sv|
|
48
|
-
load(*sv)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def load(source, value)
|
53
|
-
@stack.unshift [source, value]
|
54
|
-
end
|
55
|
-
|
56
|
-
def next
|
57
|
-
@stack.shift
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
module InstanceMethods # :nodoc:
|
62
|
-
|
63
|
-
# Setup clears the test using clear_tasks and assures that Tap::App.instance
|
64
|
-
# is the test-specific application.
|
65
|
-
def setup
|
66
|
-
super
|
67
|
-
Tap::App.instance = app
|
68
|
-
app.queue.clear
|
69
|
-
end
|
70
|
-
|
71
|
-
# Returns the test-specific application.
|
72
|
-
def app
|
73
|
-
@app ||= Tap::App.new(:root => trs.root, :directories => trs.directories)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Recieves a hash of task => expected pairs. Asserts that the last inputs for
|
77
|
-
# each task are equal to the expected inputs.
|
78
|
-
def assert_inputs(hash)
|
79
|
-
hash.each_pair do |task, expected|
|
80
|
-
inputs = task.results.collect { |r| r._input_last(task) }
|
81
|
-
assert_equal expected, inputs
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Recieves a hash of results => [index, expected] pairs. Asserts that the task result
|
86
|
-
# inputs at the specified index are equal to the expected inputs.
|
87
|
-
def assert_inputs_by_index(results, hash)
|
88
|
-
hash.each_pair do |index, expected|
|
89
|
-
assert_equal expected, results.collect {|r| r._input(index)}
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Recieves a hash of task => expected pairs. Asserts that the last outputs for
|
94
|
-
# each task are equal to the expected outputs.
|
95
|
-
def assert_outputs(hash)
|
96
|
-
hash.each_pair do |task, expected|
|
97
|
-
outputs = task.results.collect { |r| r._output_last(task) }
|
98
|
-
assert_equal expected, outputs
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# Recieves a hash of results => [index, expected] pairs. Asserts that the result
|
103
|
-
# outputs at the specified index are equal to the expected outputs.
|
104
|
-
def assert_outputs_by_index(results, hash)
|
105
|
-
hash.each_pair do |index, expected|
|
106
|
-
assert_equal expected, results.collect {|r| r._output(index)}
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# Recieves an array of audits and a hash of [index, expected_audit] pairs. Asserts that
|
111
|
-
# the collection of all [source, value] pairs in the indexed audit matches the corresponding
|
112
|
-
# pairs provided in expected_audit.
|
113
|
-
#
|
114
|
-
# Example:
|
115
|
-
# a0 = Audit.new('')
|
116
|
-
# a1 = Audit.new('')
|
117
|
-
# a1.record(:a, 'a')
|
118
|
-
# a1.record(:b, 'b')
|
119
|
-
#
|
120
|
-
# assert_audits([a0, a1], 1 => [[nil, ''], [:a, 'a'], [:b, 'b']]) # => true
|
121
|
-
#
|
122
|
-
# Note that since task results are an array of audits:
|
123
|
-
# t.results # if => [a0, a1]
|
124
|
-
# assert_audits(t1.results, 1 => [[nil, ''], [:a, 'a'], [:b, 'b']]) # then => true
|
125
|
-
#
|
126
|
-
def assert_audits(audits, hash)
|
127
|
-
hash.each_pair do |i, expected|
|
128
|
-
audit = audits[i]
|
129
|
-
raise ArgumentError.new("No audit provided at index: #{i}") if audit.nil?
|
130
|
-
|
131
|
-
actual = [collect_object_ids(audit._source_trail), audit._values].transpose
|
132
|
-
expected = expected.transpose
|
133
|
-
expected[0] = collect_object_ids(expected[0])
|
134
|
-
expected = expected.transpose
|
135
|
-
assert_equal expected, actual, "Unexpected audit for result #{i}.\nAudits displayed as: [[source.object_id, value]]"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def check_audit(audit, &block)
|
140
|
-
raise "Cannot check audit. Public method ':_from' already defined for Object." if Object.public_method_defined?(:_from)
|
141
|
-
|
142
|
-
begin
|
143
|
-
audit_stack = AuditStack.new(self)
|
144
|
-
audit_stack.load_audit(audit)
|
145
|
-
|
146
|
-
# Define the :from testing method. Defining this method on Object is good for syntax,
|
147
|
-
# but generally a bad practice. Hence, the method is undefined immediately after the
|
148
|
-
# test block completes.
|
149
|
-
#
|
150
|
-
# The from method assumes the object itself is the expected value, and that the expected
|
151
|
-
# source is given as an argument. If a block is given to from, that indicates that the value
|
152
|
-
# is the result of a merge -- the block must contain the checks to assert the origins of the
|
153
|
-
# merge value.
|
154
|
-
Object.class_eval %Q{
|
155
|
-
def _from(expected_source=nil, &block)
|
156
|
-
audit_stack = ObjectSpace._id2ref(#{audit_stack.object_id})
|
157
|
-
source, value = audit_stack.next
|
158
|
-
|
159
|
-
if block_given?
|
160
|
-
audit_stack.test.assert_equal Array, source.class, "Expected source from merge."
|
161
|
-
[source, value].transpose.reverse_each do |source, value|
|
162
|
-
source.kind_of?(Tap::Support::Audit) ?
|
163
|
-
audit_stack.load_audit(source) :
|
164
|
-
audit_stack.load(source, value)
|
165
|
-
end
|
166
|
-
yield
|
167
|
-
source, value = audit_stack.next
|
168
|
-
end
|
169
|
-
|
170
|
-
audit_stack.test.assert_equal self, value, "Wrong audit value (be sure your checks are in the correct order)"
|
171
|
-
audit_stack.test.assert_equal expected_source.object_id, source.object_id, PP.singleline_pp(value, "Wrong source id for value: ")
|
172
|
-
end}
|
173
|
-
|
174
|
-
yield
|
175
|
-
ensure
|
176
|
-
Object.class_eval %Q{remove_method(:_from)} if Object.public_method_defined?(:_from)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Applies the input options to the specified app for the duration
|
181
|
-
# of the block. Unless merge_with_existing is false, the input
|
182
|
-
# options will be merged with the existing options; otherwise
|
183
|
-
# the app options will be reconfigured to just the inputs.
|
184
|
-
#
|
185
|
-
# app = Tap::App.new(:options => {:one => 1, :two => 2})
|
186
|
-
#
|
187
|
-
# with_options({:one => 'one'}, app) do
|
188
|
-
# app.options.marshal_dump # => {:one => 'one', :two => 2}
|
189
|
-
# end
|
190
|
-
# app.options.marshal_dump # => {:one => 1, :two => 2}
|
191
|
-
#
|
192
|
-
def with_options(options, app=self.app, merge_with_existing=true, &block)
|
193
|
-
app_config = {:options => options}
|
194
|
-
with_config(app_config, app, merge_with_existing, &block)
|
195
|
-
end
|
196
|
-
|
197
|
-
# Applies the input configurations to the specified app for the
|
198
|
-
# duration of the block. Unless merge_with_existing is false,
|
199
|
-
# the input configurations will be merged with the existing
|
200
|
-
# configurations; otherwise the app will be reconfigured to
|
201
|
-
# using the inputs as specified.
|
202
|
-
#
|
203
|
-
# app = Tap::App.new(:directories => {:dir => 'dir', :alt => 'alt_dir'})
|
204
|
-
# tmp_config = {
|
205
|
-
# :directories => {:alt => 'another', :new => 'new_dir'},
|
206
|
-
# :options => {:one => 1}}
|
207
|
-
#
|
208
|
-
# with_config(tmp_config, app) do
|
209
|
-
# app.directories # => {:dir => 'dir', :alt => 'another', :new => 'new_dir'}
|
210
|
-
# app.options.marshal_dump # => {:one => 1}
|
211
|
-
# end
|
212
|
-
# app.directories # => {:dir => 'dir', :alt => 'alt_dir'}
|
213
|
-
# app.options.marshal_dump # => {}
|
214
|
-
#
|
215
|
-
def with_config(app_config, app=self.app, merge_with_existing=true, &block)
|
216
|
-
begin
|
217
|
-
hold = app.config
|
218
|
-
if merge_with_existing
|
219
|
-
hold.each_pair do |key, value|
|
220
|
-
next unless app_config.has_key?(key)
|
221
|
-
next unless value.kind_of?(Hash)
|
222
|
-
|
223
|
-
app_config[key] = value.merge(app_config[key])
|
224
|
-
end
|
225
|
-
end
|
226
|
-
app.reconfigure(app_config)
|
227
|
-
|
228
|
-
yield block if block_given?
|
229
|
-
ensure
|
230
|
-
app.reconfigure(hold)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
# assert_expected_result_files runs the input task using the
|
235
|
-
# input app config, submitting all method input files for
|
236
|
-
# processing. the assertions returns true only if all the
|
237
|
-
# expected and output files are equal. As such it is very
|
238
|
-
# convenient for file transform tasks.
|
239
|
-
#
|
240
|
-
# The default application config sets the app root to
|
241
|
-
# method_root, silences execution and directs app[:data] to
|
242
|
-
# the method output directory.
|
243
|
-
#
|
244
|
-
# assert_expected_result_files makes the input/expected
|
245
|
-
# directories if they do not exist. By default all the
|
246
|
-
# output files will be cleaned up during teardown. See
|
247
|
-
# FileMethods for more information.
|
248
|
-
def assert_expected_result_files(task, app_config={})
|
249
|
-
make_test_directories
|
250
|
-
|
251
|
-
app_config = {
|
252
|
-
:root => method_root,
|
253
|
-
:options => {:quiet => true},
|
254
|
-
:absolute_paths => {:data => method_filepath(:output)}
|
255
|
-
}.merge(app_config)
|
256
|
-
|
257
|
-
with_config(app_config, task.app) do
|
258
|
-
assert_output_files_equal do |input_files|
|
259
|
-
output_files = task.execute(*input_files).collect {|a| a._current}
|
260
|
-
block_given? ? yield(output_files) : output_files
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
private
|
266
|
-
|
267
|
-
def collect_object_ids(array)
|
268
|
-
array.collect do |s|
|
269
|
-
s.kind_of?(Array) ? collect_object_ids(s) : s.object_id
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
32
|
end
|
274
33
|
end
|
275
34
|
|
data/lib/tap/test/env_vars.rb
CHANGED
@@ -8,7 +8,9 @@ module Tap
|
|
8
8
|
# if multiple case-insensitive values are defined in ENV.
|
9
9
|
def env(type)
|
10
10
|
type = type.downcase
|
11
|
-
|
11
|
+
|
12
|
+
# ruby 1.9 returns a hash instead of an array
|
13
|
+
selected = ENV.select {|key, value| key.downcase == type}.to_a
|
12
14
|
|
13
15
|
case selected.length
|
14
16
|
when 0 then nil
|
@@ -17,10 +19,10 @@ module Tap
|
|
17
19
|
raise "Multiple env values for '#{type}'"
|
18
20
|
end
|
19
21
|
end
|
20
|
-
|
21
|
-
# Returns true if the env_var(var) is set and matches /^true%/i
|
22
|
-
def env_true?(var)
|
23
|
-
env(var) && env(var) =~ /^true$/i
|
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
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -2,32 +2,29 @@ require 'tap/root'
|
|
2
2
|
require 'tap/test/env_vars'
|
3
3
|
require 'test/unit'
|
4
4
|
require 'fileutils'
|
5
|
+
require 'active_support/core_ext/class'
|
5
6
|
|
6
7
|
module Test # :nodoc:
|
7
8
|
module Unit # :nodoc:
|
8
|
-
# Methods extending TestCase. See the TestTutorial for more information.
|
9
9
|
class TestCase
|
10
10
|
class << self
|
11
11
|
|
12
12
|
# Causes a TestCase to act as a file test, by instantiating a class Tap::Root
|
13
|
-
# (trs), and including
|
13
|
+
# (trs), and including FileMethods. The root and directories used to
|
14
14
|
# instantiate trs can be specified as options. By default file_test_root
|
15
|
-
# and
|
15
|
+
# and the directories {:input => 'input', :output => 'output', :expected => 'expected'}
|
16
|
+
# will be used.
|
16
17
|
#
|
17
|
-
#
|
18
|
-
# acts_as_file_test(:root => file_test_root, :directories => default_directories)
|
19
|
-
# end
|
20
|
-
#
|
21
|
-
# Note: file_test_root determines a root directory +based on the calling file+.
|
18
|
+
# Note: file_test_root determines a root directory <em>based on the calling file</em>.
|
22
19
|
# Be sure to specify the root directory explicitly if you call acts_as_file_test
|
23
20
|
# from a file that is NOT meant to be test file.
|
24
21
|
def acts_as_file_test(options={})
|
25
22
|
options = {
|
26
23
|
:root => file_test_root,
|
27
|
-
:directories => {}
|
28
|
-
}.merge(options
|
24
|
+
:directories => {:input => 'input', :output => 'output', :expected => 'expected'}
|
25
|
+
}.merge(options)
|
29
26
|
|
30
|
-
directories =
|
27
|
+
directories = options[:directories]
|
31
28
|
trs = Tap::Root.new(options[:root], directories)
|
32
29
|
|
33
30
|
write_inheritable_attribute(:trs, trs)
|
@@ -35,15 +32,6 @@ module Test # :nodoc:
|
|
35
32
|
|
36
33
|
include Tap::Test::FileMethods
|
37
34
|
end
|
38
|
-
|
39
|
-
# The default directories for a file test:
|
40
|
-
#
|
41
|
-
# :input => 'input'
|
42
|
-
# :output => 'output'
|
43
|
-
# :expected => 'expected'
|
44
|
-
def default_directories
|
45
|
-
{:input => 'input', :output => 'output', :expected => 'expected'}
|
46
|
-
end
|
47
35
|
|
48
36
|
# Infers the test root directory from the calling file. Ex:
|
49
37
|
# 'some_class.rb' => 'some_class'
|
@@ -69,80 +57,84 @@ end
|
|
69
57
|
module Tap
|
70
58
|
module Test
|
71
59
|
|
72
|
-
# ==
|
60
|
+
# == Overview
|
73
61
|
#
|
74
62
|
# FileMethods sets up a TestCase with methods for accessing and utilizing
|
75
|
-
# test-specific files and directories. Each class
|
63
|
+
# test-specific files and directories. Each class that acts_as_file_test
|
76
64
|
# is set up with a Tap::Root structure (trs) that mediates the creation of
|
77
|
-
# test method filepaths.
|
78
|
-
# acts_as_file_test to include the FileMethods and initialize the trs.
|
65
|
+
# test method filepaths.
|
79
66
|
#
|
80
|
-
# class
|
67
|
+
# class FileMethodsDocTest < Test::Unit::TestCase
|
81
68
|
# acts_as_file_test
|
82
|
-
#
|
83
|
-
# def
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
69
|
+
#
|
70
|
+
# def test_something
|
71
|
+
# # dir = File.expand_path( File.dirname(__FILE__) )
|
72
|
+
# trs.root # => dir + "/file_methods_doc",
|
73
|
+
# method_root # => dir + "/file_methods_doc/test_something",
|
74
|
+
# method_dir(:input) # => dir + "/file_methods_doc/test_something/input"
|
87
75
|
# end
|
88
76
|
# end
|
89
77
|
#
|
90
|
-
#
|
78
|
+
# === assert_files
|
91
79
|
#
|
92
80
|
# FileMethods is specifically designed for tests that transform a set of input
|
93
81
|
# files into output files. For this type of test, input and expected files can
|
94
82
|
# placed into their respective directories then used within the context of
|
95
|
-
#
|
96
|
-
# files.
|
83
|
+
# assert_files to ensure the output files are equal to the expected files.
|
97
84
|
#
|
98
85
|
# For example, lets define a test that transforms input files into output files
|
99
86
|
# in a trivial way, simply by replacing 'input' with 'output' in the file.
|
100
87
|
#
|
101
|
-
# class
|
88
|
+
# class FileMethodsDocTest < Test::Unit::TestCase
|
102
89
|
# acts_as_file_test
|
103
|
-
#
|
104
|
-
# def
|
105
|
-
#
|
90
|
+
#
|
91
|
+
# def test_sub
|
92
|
+
# assert_files do |input_files|
|
106
93
|
# input_files.collect do |filepath|
|
107
94
|
# input = File.read(filepath)
|
108
|
-
# output_file = method_filepath(:
|
95
|
+
# output_file = method_filepath(:output, File.basename(filepath))
|
109
96
|
#
|
110
97
|
# File.open(output_file, "w") do |f|
|
111
98
|
# f << input.gsub(/input/, "output")
|
112
99
|
# end
|
100
|
+
#
|
101
|
+
# output_file
|
113
102
|
# end
|
114
103
|
# end
|
115
104
|
# end
|
116
105
|
# end
|
117
106
|
#
|
118
|
-
# Now
|
107
|
+
# Now say you had some input and expected files for the 'test_sub' method:
|
119
108
|
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
# [file_one.txt", file_two.txt"].each_with_index do |basename, i|
|
124
|
-
# input = "file_test/test_transform/input_files/" + basename
|
125
|
-
# File.open(input, "w") {|f| f << "test input #{i}"}
|
109
|
+
# [file_methods_doc/test_sub/input/one.txt]
|
110
|
+
# test input 1
|
126
111
|
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
112
|
+
# [file_methods_doc/test_sub/input/two.txt]
|
113
|
+
# test input 2
|
114
|
+
#
|
115
|
+
# [file_methods_doc/test_sub/expected/one.txt]
|
116
|
+
# test output 1
|
130
117
|
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
# block makes output files in "file_test/test_transform/output_files",
|
134
|
-
# and then assert_output_files_equal compares the files and finds they
|
135
|
-
# are equal. As a result the test passes.
|
118
|
+
# [file_methods_doc/test_sub/expected/two.txt]
|
119
|
+
# test output 2
|
136
120
|
#
|
137
|
-
#
|
138
|
-
#
|
121
|
+
# When you run the FileMethodsDocTest test, the test_sub test will pass
|
122
|
+
# the input files to the assert_files block. Then assert_files compares
|
123
|
+
# the returned filepaths with the expected files translated from the
|
124
|
+
# expected directory to the output directory. In this case, the files
|
125
|
+
# are equal and the test passes.
|
139
126
|
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
# output files for just the tests that fail (KEEP_FAILURES). These flags
|
144
|
-
# can easily be specified from the command line when running a rake task:
|
127
|
+
# The test fails if the returned files aren't equal to the expected files,
|
128
|
+
# either because there are missing or extra files, or if the file contents
|
129
|
+
# are different.
|
145
130
|
#
|
131
|
+
# When the test completes, the teardown method cleans up the output directory.
|
132
|
+
# For ease in debugging, ENV variable flags can be specified to keep all
|
133
|
+
# output files (KEEP_OUTPUTS) or to keep the output files for just the tests
|
134
|
+
# that fail (KEEP_FAILURES). These flags can be specified from the command
|
135
|
+
# line if you're running the tests with rake or tap:
|
136
|
+
#
|
137
|
+
# % rake test keep_outputs=true
|
146
138
|
# % tap run test keep_failures=true
|
147
139
|
#
|
148
140
|
module FileMethods
|
@@ -156,7 +148,7 @@ module Tap
|
|
156
148
|
# Creates the trs.directories, specific to the method calling make_test_directories
|
157
149
|
def make_test_directories
|
158
150
|
trs.directories.values.each do |dir|
|
159
|
-
FileUtils.mkdir_p( File.join(trs.root,
|
151
|
+
FileUtils.mkdir_p( File.join(trs.root, method_name_str, dir) )
|
160
152
|
end
|
161
153
|
end
|
162
154
|
|
@@ -188,16 +180,21 @@ module Tap
|
|
188
180
|
try_remove_dir(method_root)
|
189
181
|
try_remove_dir(trs.root)
|
190
182
|
end
|
183
|
+
|
184
|
+
# Returns method_name as a string (Ruby 1.9 symbolizes method_name)
|
185
|
+
def method_name_str
|
186
|
+
method_name.to_s
|
187
|
+
end
|
191
188
|
|
192
189
|
# The method_root directory is defined as trs.filepath(method_name)
|
193
|
-
def method_root(method=
|
190
|
+
def method_root(method=method_name_str)
|
194
191
|
trs.filepath(method)
|
195
192
|
end
|
196
193
|
|
197
194
|
# The method directory is defined as 'dir/method', where method is the calling method
|
198
195
|
# by default. method_dir returns the method directory if it exists, otherwise it returns
|
199
196
|
# trs[dir].
|
200
|
-
def method_dir(dir, method=
|
197
|
+
def method_dir(dir, method=method_name_str)
|
201
198
|
File.join(method_root(method), trs.directories[dir] || dir.to_s)
|
202
199
|
end
|
203
200
|
|
@@ -209,7 +206,7 @@ module Tap
|
|
209
206
|
end
|
210
207
|
|
211
208
|
# Returns a filepath constructed from the method directory if it exists,
|
212
|
-
#
|
209
|
+
# otherwise the filepath will be constructed from <tt>trs[dir]</tt>.
|
213
210
|
def method_filepath(dir, *filenames)
|
214
211
|
File.join(method_dir(dir), *filenames)
|
215
212
|
end
|
@@ -236,7 +233,7 @@ module Tap
|
|
236
233
|
# files within it. Raises an error if the removal does not succeed.
|
237
234
|
def clear_method_dir(dir)
|
238
235
|
# clear out the folder if it exists
|
239
|
-
dir_path = method_dir(dir,
|
236
|
+
dir_path = method_dir(dir, method_name_str)
|
240
237
|
FileUtils.rm_r(dir_path) if File.exists?(dir_path)
|
241
238
|
end
|
242
239
|
|
@@ -260,8 +257,8 @@ module Tap
|
|
260
257
|
# - The extension is chomped off the end of the filename
|
261
258
|
# - If the directory for the filepath does not exist, the directory will be created
|
262
259
|
# - Like all files in the output directory, tempfiles will be deleted by the default
|
263
|
-
#
|
264
|
-
def
|
260
|
+
# +teardown+ method
|
261
|
+
def output_tempfile(filename=method_name_str)
|
265
262
|
n = 0
|
266
263
|
ext = File.extname(filename)
|
267
264
|
basename = filename.chomp(ext)
|
@@ -275,88 +272,96 @@ module Tap
|
|
275
272
|
FileUtils.mkdir_p(dirname) unless File.exists?(dirname)
|
276
273
|
filepath
|
277
274
|
end
|
278
|
-
|
279
|
-
# Asserts that each pair of input files are equal, using FileUtils.cmp.
|
280
|
-
def files_equal?(a, b)
|
281
|
-
FileUtils.cmp(a, b)
|
282
|
-
end
|
283
|
-
|
284
|
-
# Asserts that each pair of input files produce an equivalent object when
|
285
|
-
# loaded as a yaml file.
|
286
|
-
def yml_equal?(a, b)
|
287
|
-
YAML.load_file(a) == YAML.load_file(b)
|
288
|
-
end
|
289
275
|
|
290
|
-
# Yields to the input block for each pair of
|
291
|
-
# if the input arrays do not have equal
|
292
|
-
|
276
|
+
# Yields to the input block for each pair of entries in the input
|
277
|
+
# arrays. An error is raised if the input arrays do not have equal
|
278
|
+
# numbers of entries.
|
279
|
+
def each_pair(a, b, &block) # :yields: entry_a, entry_b,
|
280
|
+
each_pair_with_index(a,b) do |entry_a, entry_b, index|
|
281
|
+
yield(entry_a, entry_b)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# Same as each_pair but yields the index of the entries as well.
|
286
|
+
def each_pair_with_index(a, b, &block) # :yields: entry_a, entry_b, index
|
293
287
|
a = [a] unless a.kind_of?(Array)
|
294
288
|
b = [b] unless b.kind_of?(Array)
|
295
289
|
|
296
290
|
raise ArgumentError, "The input arrays must have an equal number of entries." unless a.length == b.length
|
297
|
-
a.
|
298
|
-
yield(a[index], b[index])
|
291
|
+
0.upto(a.length-1) do |index|
|
292
|
+
yield(a[index], b[index], index)
|
299
293
|
end
|
300
294
|
end
|
301
295
|
|
302
|
-
|
296
|
+
# assert_files runs a file-based test that feeds all files in method_dir(:input)
|
297
|
+
# to the block, then compares the resulting files (which should be relative to
|
298
|
+
# method_dir(:output)) with all the files in method_dir(:expected). Note that
|
299
|
+
# since only the files returned by the block are used in the comparison,
|
300
|
+
# additional files in the output directory are effectively ignored.
|
301
|
+
#
|
302
|
+
# A variety of options can be specified to adjust the behavior:
|
303
|
+
#
|
304
|
+
# :input_files specify the input files to pass to the block
|
305
|
+
# :expected_files specify the expected files used in comparison
|
306
|
+
# :include_input_directories specifies directories to be included in the
|
307
|
+
# input_files array (by default dirs are excluded)
|
308
|
+
# :include_expected_directories specifies directories to be included in the
|
309
|
+
# expected-output file list comparison (by default
|
310
|
+
# dirs are excluded, note that naturally only files
|
311
|
+
# have their actual content compared)
|
312
|
+
#
|
313
|
+
# Option keys should be symbols. assert_files will fail if :expected_files was
|
314
|
+
# not specified in the options and no files were found in method_dir(:expected).
|
315
|
+
# This tries to prevent silent false-positive results when you forget to put
|
316
|
+
# expected files in their place.
|
317
|
+
def assert_files(options={}) # :yields: input_files
|
303
318
|
make_test_directories
|
304
319
|
|
305
320
|
options = {
|
306
321
|
:input_files => nil,
|
307
322
|
:expected_files => nil,
|
308
|
-
|
309
|
-
:
|
310
|
-
:
|
311
|
-
:include_directories => false
|
323
|
+
|
324
|
+
:include_input_directories => false,
|
325
|
+
:include_expected_directories => false
|
312
326
|
}.merge(options)
|
313
327
|
|
314
|
-
#
|
328
|
+
# Get the input and expected files in this manner:
|
329
|
+
# - look for manually specified files
|
330
|
+
# - glob for files if none were specified
|
331
|
+
# - expand paths and sort
|
332
|
+
# - remove directories unless specified not to do so
|
315
333
|
input_files, expected_files = [:input, :expected].collect do |key|
|
316
|
-
|
317
|
-
|
318
|
-
files = options.delete(options_key)
|
334
|
+
files = options["#{key}_files".to_sym]
|
319
335
|
files = method_glob(key) if files.nil?
|
320
|
-
files =
|
321
|
-
|
322
|
-
unless options[
|
336
|
+
files = [files].flatten.collect {|file| File.expand_path(file) }.sort
|
337
|
+
|
338
|
+
unless options["include_#{key}_directories".to_sym]
|
323
339
|
files.delete_if {|file| File.directory?(file)}
|
324
340
|
end
|
341
|
+
|
325
342
|
files
|
326
343
|
end
|
327
|
-
|
328
|
-
flunk "No expected files were specfied." if options[:require_expected_files] && expected_files.empty?
|
329
|
-
|
330
|
-
# create output files
|
331
|
-
output_files = if options[:iterate_inputs]
|
332
|
-
input_files.collect do |input_file|
|
333
|
-
yield(input_file)
|
334
|
-
end
|
335
|
-
else
|
336
|
-
yield(input_files)
|
337
|
-
end
|
338
|
-
output_files = output_files.flatten.collect {|file| File.expand_path(file) }
|
339
344
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
expected_output_files.delete_if {|file| File.directory?(file)}
|
344
|
-
end
|
345
|
-
expected_output_files.collect! {|file| File.expand_path(file) }
|
346
|
-
|
347
|
-
# assure there are no missing or extra output files
|
348
|
-
assert_equal expected_output_files, output_files, "Missing or extra output files"
|
345
|
+
# check at least one expected file was found
|
346
|
+
if expected_files.empty? && options[:expected_files] == nil
|
347
|
+
flunk "No expected files specified."
|
349
348
|
end
|
349
|
+
|
350
|
+
# get output files from the block, expand and sort
|
351
|
+
output_files = [yield(input_files)].flatten.collect do |output_file|
|
352
|
+
output_file = File.expand_path(output_file)
|
353
|
+
end.sort
|
350
354
|
|
351
355
|
# check that the expected and output filepaths are the same
|
352
|
-
|
353
|
-
|
354
|
-
|
356
|
+
translated_expected_files = expected_files.collect do |expected_file|
|
357
|
+
method_translate(expected_file, :expected, :output)
|
358
|
+
end
|
359
|
+
assert_equal translated_expected_files, output_files, "Missing, extra, or unexpected output files"
|
355
360
|
|
356
361
|
# check that the expected and output file contents are equal
|
357
362
|
errors = []
|
358
363
|
each_pair(expected_files, output_files) do |expected_file, output_file|
|
359
|
-
unless
|
364
|
+
unless (File.directory?(expected_file) && File.directory?(output_file)) || FileUtils.cmp(expected_file, output_file)
|
360
365
|
errors << "<#{expected_file}> not equal to\n<#{output_file}>"
|
361
366
|
end
|
362
367
|
end
|
@@ -365,7 +370,7 @@ module Tap
|
|
365
370
|
|
366
371
|
private
|
367
372
|
|
368
|
-
def make_tmpname(basename, n, ext="")
|
373
|
+
def make_tmpname(basename, n, ext="") # :nodoc:
|
369
374
|
method_filepath(:output, sprintf('%s%d.%d%s', basename, $$, n, ext))
|
370
375
|
end
|
371
376
|
end
|