tap 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History +9 -0
- data/README +1 -0
- data/bin/tap +7 -45
- data/cmd/manifest.rb +94 -0
- data/cmd/run.rb +1 -1
- data/lib/tap.rb +0 -5
- data/lib/tap/constants.rb +1 -1
- data/lib/tap/env.rb +195 -187
- data/lib/tap/exe.rb +63 -0
- data/lib/tap/file_task.rb +33 -8
- data/lib/tap/generator/base.rb +7 -28
- data/lib/tap/generator/generators/root/root_generator.rb +21 -15
- data/lib/tap/generator/generators/root/templates/Rakefile +1 -1
- data/lib/tap/generator/generators/root/templates/gemspec +2 -1
- data/lib/tap/patches/rake/testtask.rb +2 -0
- data/lib/tap/support/class_configuration.rb +5 -6
- data/lib/tap/support/configurable_class.rb +15 -18
- data/lib/tap/support/configuration.rb +8 -6
- data/lib/tap/support/declarations.rb +2 -2
- data/lib/tap/support/framework.rb +14 -2
- data/lib/tap/support/framework_class.rb +13 -32
- data/lib/tap/support/gems.rb +63 -0
- data/lib/tap/support/gems/rake.rb +90 -0
- data/lib/tap/support/instance_configuration.rb +8 -8
- data/lib/tap/support/lazy_attributes.rb +30 -0
- data/lib/tap/support/lazydoc.rb +65 -33
- data/lib/tap/support/manifest.rb +117 -54
- data/lib/tap/tasks/rake.rb +1 -0
- data/lib/tap/test/script_methods.rb +34 -71
- data/lib/tap/test/script_methods/script_test.rb +98 -0
- data/lib/tap/test/tap_methods.rb +1 -5
- data/lib/tap/workflow.rb +47 -34
- metadata +8 -2
data/lib/tap/support/manifest.rb
CHANGED
@@ -1,88 +1,151 @@
|
|
1
|
+
require 'tap/root'
|
2
|
+
|
1
3
|
module Tap
|
2
4
|
module Support
|
3
|
-
class Manifest
|
4
|
-
|
5
|
+
class Manifest
|
5
6
|
class << self
|
6
|
-
def
|
7
|
-
"
|
8
|
-
end
|
9
|
-
|
10
|
-
def map_method(name)
|
11
|
-
"manifest_map_#{name}".to_sym
|
7
|
+
def normalize(key)
|
8
|
+
key.to_s.downcase.gsub(/\s/, "_").delete(":")
|
12
9
|
end
|
13
10
|
end
|
14
11
|
|
15
|
-
|
16
|
-
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
# An array of (key, value) entries in self.
|
17
15
|
attr_reader :entries
|
18
|
-
attr_reader :map_method
|
19
|
-
attr_reader :paths
|
20
|
-
attr_reader :path_index
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
17
|
+
# An array of search_paths to identify entries.
|
18
|
+
attr_reader :search_paths
|
19
|
+
|
20
|
+
# The index of the search_path that will be searched
|
21
|
+
# next when building the manifest.
|
22
|
+
attr_reader :search_path_index
|
23
|
+
|
24
|
+
def initialize(search_paths)
|
25
|
+
self.search_paths = search_paths
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns an array of the entries keys.
|
29
|
+
def keys
|
30
|
+
entries.collect {|(key, value)| key }
|
30
31
|
end
|
31
32
|
|
32
|
-
|
33
|
-
|
33
|
+
# Returns an array of the entries values.
|
34
|
+
def values
|
35
|
+
entries.collect {|(key, value)| value }
|
34
36
|
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
n_to_skip = @path_index
|
40
|
-
paths.each do |context, path|
|
41
|
-
if n_to_skip > 0
|
42
|
-
n_to_skip -= 1
|
43
|
-
next
|
44
|
-
end
|
45
|
-
|
46
|
-
@path_index += 1
|
47
|
-
yield(context, path)
|
48
|
-
end
|
49
|
-
|
50
|
-
true
|
38
|
+
# True if entries are empty.
|
39
|
+
def empty?
|
40
|
+
entries.empty?
|
51
41
|
end
|
52
42
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
if existing_key && existing_path != entry[1]
|
59
|
-
raise ManifestConflict, "multiple paths for key '#{existing_key}': ['#{existing_path}', '#{entry[1]}']"
|
60
|
-
end
|
43
|
+
def search_paths=(search_paths)
|
44
|
+
@entries = []
|
45
|
+
@search_paths = search_paths
|
46
|
+
@search_path_index = 0
|
47
|
+
end
|
61
48
|
|
62
|
-
|
49
|
+
# Clears entries and sets the search_path_index to zero.
|
50
|
+
def reset
|
51
|
+
@entries.clear
|
52
|
+
@search_path_index = 0
|
63
53
|
end
|
64
54
|
|
65
|
-
|
66
|
-
|
55
|
+
# Builds the manifest, identifying all entries from search_paths.
|
56
|
+
# Returns self.
|
57
|
+
def build
|
58
|
+
each {|k, v|} unless built?
|
59
|
+
self
|
67
60
|
end
|
68
61
|
|
69
|
-
|
70
|
-
|
62
|
+
# True if all search paths have been checked for entries
|
63
|
+
# (ie search_path_index == search_paths.length).
|
64
|
+
def built?
|
65
|
+
@search_path_index == search_paths.length
|
66
|
+
end
|
67
|
+
|
68
|
+
# Abstract method which should return each (key, value) entry
|
69
|
+
# for a given search path. Raises a NotImplementedError
|
70
|
+
# if left not implemented.
|
71
|
+
def entries_for(search_path)
|
72
|
+
[[search_path, search_path]]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Adds the (key, value) pair to entries and returns the new entry.
|
76
|
+
# Checks that entries does not already assign key a conflicting value;
|
77
|
+
# raises an error if this is the case, or returns the existing entry.
|
78
|
+
#
|
79
|
+
# Keys are normalized using Manifest.normalize before storing.
|
80
|
+
def store(key, value)
|
81
|
+
key = Manifest.normalize(key)
|
82
|
+
existing = entries.find {|(k, v)| key == k }
|
83
|
+
|
84
|
+
if existing
|
85
|
+
if existing[1] != value
|
86
|
+
raise ManifestConflict.new(key, value, existing[1])
|
87
|
+
else
|
88
|
+
return existing
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
new_entry = [key, value]
|
93
|
+
entries << new_entry
|
94
|
+
new_entry
|
71
95
|
end
|
72
96
|
|
73
|
-
|
74
|
-
|
97
|
+
# Iterates over each (key, value) entry in self, dynamically identifying entries
|
98
|
+
# from search_paths if necessary. New entries are identifed using the each_for
|
99
|
+
# method.
|
100
|
+
def each
|
101
|
+
entries.each do |key, path|
|
102
|
+
yield(key, path)
|
103
|
+
end
|
75
104
|
|
105
|
+
unless built?
|
106
|
+
n_to_skip = @search_path_index
|
107
|
+
search_paths.each do |search_path|
|
108
|
+
# advance to the current search path
|
109
|
+
if n_to_skip > 0
|
110
|
+
n_to_skip -= 1
|
111
|
+
next
|
112
|
+
end
|
113
|
+
@search_path_index += 1
|
114
|
+
|
115
|
+
# collect new entries and yield afterwards to ensure
|
116
|
+
# that all entries for the search_path get stored
|
117
|
+
new_entries = entries_for(*search_path)
|
118
|
+
next if new_entries == nil
|
119
|
+
|
120
|
+
new_entries.each {|(key, value)| store(key, value) }
|
121
|
+
new_entries.each {|(key, value)| yield(key, value) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns an array of (mini_key, value) pairs, matching
|
127
|
+
# entries by index.
|
128
|
+
def minimize
|
76
129
|
hash = {}
|
77
|
-
Root.minimize(keys) do |path, mini_path|
|
130
|
+
Tap::Root.minimize(keys) do |path, mini_path|
|
78
131
|
hash[path] = mini_path
|
79
132
|
end
|
80
133
|
|
81
134
|
entries.collect {|path, value| [hash[path], value] }
|
82
135
|
end
|
83
136
|
|
137
|
+
protected
|
138
|
+
|
84
139
|
# Raised when multiple paths are assigned to the same manifest key.
|
85
140
|
class ManifestConflict < StandardError
|
141
|
+
attr_reader :key, :value, :existing
|
142
|
+
|
143
|
+
def initialize(key, value, existing)
|
144
|
+
@key = key
|
145
|
+
@value = value
|
146
|
+
@existing = existing
|
147
|
+
super("attempted to store '%s': %s\nbut already was\n%s" % [key, value, existing])
|
148
|
+
end
|
86
149
|
end
|
87
150
|
end
|
88
151
|
end
|
data/lib/tap/tasks/rake.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'tap/test/file_methods'
|
3
3
|
require 'tap/test/subset_methods'
|
4
|
-
|
4
|
+
require 'tap/test/script_methods/script_test'
|
5
5
|
|
6
6
|
module Test # :nodoc:
|
7
7
|
module Unit # :nodoc:
|
@@ -25,36 +25,15 @@ end
|
|
25
25
|
|
26
26
|
module Tap
|
27
27
|
module Test
|
28
|
-
|
29
28
|
module ScriptMethods
|
30
|
-
|
31
|
-
|
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)
|
29
|
+
|
30
|
+
def assert_output_equal(a, b, msg)
|
51
31
|
a = a[1..-1] if a[0] == ?\n
|
52
32
|
if a == b
|
53
33
|
assert true
|
54
34
|
else
|
55
35
|
flunk %Q{
|
56
36
|
#{msg}
|
57
|
-
% #{cmd}
|
58
37
|
==================== expected output ====================
|
59
38
|
#{a.gsub(/\t/, "\\t").gsub(/\r\n/, "\\r\\n\n").gsub(/\n/, "\\n\n")}
|
60
39
|
======================== but was ========================
|
@@ -64,13 +43,12 @@ module Tap
|
|
64
43
|
end
|
65
44
|
end
|
66
45
|
|
67
|
-
def assert_alike(a, b,
|
46
|
+
def assert_alike(a, b, msg)
|
68
47
|
if b =~ a
|
69
48
|
assert true
|
70
49
|
else
|
71
50
|
flunk %Q{
|
72
51
|
#{msg}
|
73
|
-
% #{cmd}
|
74
52
|
================= expected output like ==================
|
75
53
|
#{a}
|
76
54
|
======================== but was ========================
|
@@ -80,58 +58,43 @@ module Tap
|
|
80
58
|
end
|
81
59
|
end
|
82
60
|
|
83
|
-
def
|
61
|
+
def with_argv(argv=[])
|
62
|
+
current_argv = ARGV.dup
|
63
|
+
begin
|
64
|
+
ARGV.clear
|
65
|
+
ARGV.concat(argv)
|
66
|
+
|
67
|
+
yield
|
68
|
+
|
69
|
+
ensure
|
70
|
+
ARGV.clear
|
71
|
+
ARGV.concat(current_argv)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def default_command_path
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def script_test(test_dir=method_root)
|
84
80
|
subset_test("SCRIPT", "s") do
|
85
|
-
|
86
|
-
yield(
|
81
|
+
cmd = ScriptTest.new(default_command_path)
|
82
|
+
yield(cmd)
|
87
83
|
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
84
|
+
Tap::Root.indir(test_dir, true) do
|
85
|
+
with_argv do
|
86
|
+
puts "\n# == #{method_name}"
|
101
87
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
88
|
+
cmd.run(env('stepwise')) do |expected, result, msg|
|
89
|
+
case expected
|
90
|
+
when String
|
91
|
+
assert_output_equal(expected, result, msg)
|
92
|
+
when Regexp
|
93
|
+
assert_alike(expected, result, msg)
|
124
94
|
end
|
125
|
-
else
|
126
|
-
puts "%.3fs : %s" % [elapsed, msg]
|
127
95
|
end
|
128
96
|
end
|
129
|
-
ensure
|
130
|
-
Dir.chdir(current_dir)
|
131
|
-
ARGV.clear
|
132
|
-
ARGV.concat(current_argv)
|
133
97
|
end
|
134
|
-
|
135
98
|
end
|
136
99
|
end
|
137
100
|
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'tap/support/shell_utils'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Test
|
5
|
+
module ScriptMethods
|
6
|
+
class ScriptTest
|
7
|
+
include Tap::Support::ShellUtils
|
8
|
+
|
9
|
+
# The command path for self, returned by to_s
|
10
|
+
attr_accessor :command_path
|
11
|
+
|
12
|
+
# An array of (command, message, expected, validation)
|
13
|
+
# entries, representing the accumulated test commands.
|
14
|
+
attr_reader :commands
|
15
|
+
|
16
|
+
def initialize(command_path=nil)
|
17
|
+
@command_path = command_path
|
18
|
+
@commands = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Splits the input string, collecting single-line commands
|
22
|
+
# and expected results. Nil will be used as the expected
|
23
|
+
# result if the result is whitespace, or not present.
|
24
|
+
#
|
25
|
+
# cmd = ScriptTest.new
|
26
|
+
# cmd.split %Q{
|
27
|
+
# % command one
|
28
|
+
# expected text for command one
|
29
|
+
# % command two
|
30
|
+
# % command three
|
31
|
+
# expected text for command three
|
32
|
+
# }
|
33
|
+
# # => [
|
34
|
+
# # ["command one", "expected text for command one\n"],
|
35
|
+
# # ["command two", nil],
|
36
|
+
# # ["command three", "expected text for command three\n"]]
|
37
|
+
#
|
38
|
+
def split(str)
|
39
|
+
str.split(/^%\s*/).collect do |s|
|
40
|
+
next(nil) if s.strip.empty?
|
41
|
+
command, expected = s.split(/\n/, 2)
|
42
|
+
expected = nil if expected && expected.strip.empty?
|
43
|
+
[command.strip, expected]
|
44
|
+
end.compact
|
45
|
+
end
|
46
|
+
|
47
|
+
def time(msg, command)
|
48
|
+
commands << [command, msg, nil, nil]
|
49
|
+
end
|
50
|
+
|
51
|
+
def check(msg, command, &validation)
|
52
|
+
new_commands = split(command)
|
53
|
+
new_commands.each_with_index do |(cmd, expected), i|
|
54
|
+
commands << [cmd, (new_commands.length > 1 ? "#{msg} (#{i})" : msg), expected, validation]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def match(msg, command, regexp=nil, &validation)
|
59
|
+
new_commands = split(command)
|
60
|
+
new_commands.each_with_index do |(cmd, expected), i|
|
61
|
+
raise "expected text specified in match command" unless expected == nil
|
62
|
+
commands << [cmd, (new_commands.length > 1 ? "#{msg} (#{i})" : msg), regexp, validation]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def run(stepwise=false)
|
67
|
+
commands.each do |cmd, msg, expected, validation|
|
68
|
+
start = Time.now
|
69
|
+
result = capture_sh(cmd) {|ok, status, tempfile_path| }
|
70
|
+
elapsed = Time.now - start
|
71
|
+
|
72
|
+
yield(expected, result, %Q{#{msg}\n% #{cmd}}) if expected
|
73
|
+
validation.call(result) if validation
|
74
|
+
|
75
|
+
if stepwise
|
76
|
+
print %Q{
|
77
|
+
------------------------------------
|
78
|
+
%s
|
79
|
+
> %s
|
80
|
+
%s
|
81
|
+
Time Elapsed: %.3fs} % [msg, cmd, result, elapsed]
|
82
|
+
|
83
|
+
print "\nContinue? (y/n): "
|
84
|
+
break if gets.strip =~ /^no?$/i
|
85
|
+
else
|
86
|
+
puts "%.3fs : %s" % [elapsed, msg]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the command path.
|
92
|
+
def to_s
|
93
|
+
command_path
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|