autotest-standalone 4.5.0
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/.autotest +18 -0
- data/.gitignore +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +38 -0
- data/History.txt +709 -0
- data/Rakefile +66 -0
- data/Readme.md +93 -0
- data/VERSION +1 -0
- data/articles/getting_started_with_autotest.html +533 -0
- data/autotest-standalone.gemspec +63 -0
- data/bin/autotest +7 -0
- data/bin/unit_diff +44 -0
- data/example_dot_autotest.rb +12 -0
- data/lib/autotest.rb +822 -0
- data/lib/autotest/autoupdate.rb +26 -0
- data/lib/autotest/bundler.rb +10 -0
- data/lib/autotest/once.rb +9 -0
- data/lib/autotest/rcov.rb +27 -0
- data/lib/autotest/restart.rb +12 -0
- data/lib/autotest/timestamp.rb +9 -0
- data/lib/unit_diff.rb +272 -0
- data/test/helper.rb +6 -0
- data/test/test_autotest.rb +520 -0
- data/test/test_autotest_integration.rb +95 -0
- data/test/test_unit_diff.rb +335 -0
- metadata +96 -0
@@ -0,0 +1,26 @@
|
|
1
|
+
module Autotest::AutoUpdate
|
2
|
+
@@sleep_time, @@update_cmd, @@updater = 60, "svn up", nil
|
3
|
+
|
4
|
+
def self.sleep_time= o
|
5
|
+
@@sleep_time = o
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.update_cmd= o
|
9
|
+
@@update_cmd = o
|
10
|
+
end
|
11
|
+
|
12
|
+
Autotest.add_hook :run_command do |at|
|
13
|
+
@@updater.kill if @@updater
|
14
|
+
end
|
15
|
+
|
16
|
+
Autotest.add_hook :ran_command do |at|
|
17
|
+
@@updater = Thread.start do
|
18
|
+
loop do
|
19
|
+
puts "# Waiting for #{@@sleep_time} seconds before updating"
|
20
|
+
sleep @@sleep_time
|
21
|
+
puts "# Running #{@@update_cmd}"
|
22
|
+
system @@update_cmd
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Autotest::RCov
|
2
|
+
@@command, @@options = "rcov", nil
|
3
|
+
|
4
|
+
def self.command= o
|
5
|
+
@@command = o
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.pattern= o
|
9
|
+
warn "RCov.pattern= no longer has any functionality. please remove."
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.options= o
|
13
|
+
@@options = o
|
14
|
+
end
|
15
|
+
|
16
|
+
Autotest.add_hook :all_good do |at|
|
17
|
+
options = @@options ? "RCOVOPTS=\"#{@@options}\"" : ""
|
18
|
+
system "rake #{@@command} #{options}"
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
Autotest.add_hook :initialize do |at|
|
23
|
+
at.add_exception 'coverage'
|
24
|
+
at.add_exception 'coverage.info'
|
25
|
+
false
|
26
|
+
end
|
27
|
+
end
|
data/lib/unit_diff.rb
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
##
|
4
|
+
# UnitDiff makes reading Test::Unit output easy and fun. Instead of a
|
5
|
+
# confusing jumble of text with nearly unnoticable changes like this:
|
6
|
+
#
|
7
|
+
# 1) Failure:
|
8
|
+
# test_to_gpoints(RouteTest) [test/unit/route_test.rb:29]:
|
9
|
+
# <"new GPolyline([\n new GPoint( 47.00000, -122.00000),\n new GPoint( 46.5000
|
10
|
+
# 0, -122.50000),\n new GPoint( 46.75000, -122.75000),\n new GPoint( 46.00000,
|
11
|
+
# -123.00000)])"> expected but was
|
12
|
+
# <"new Gpolyline([\n new GPoint( 47.00000, -122.00000),\n new GPoint( 46.5000
|
13
|
+
# 0, -122.50000),\n new GPoint( 46.75000, -122.75000),\n new GPoint( 46.00000,
|
14
|
+
# -123.00000)])">.
|
15
|
+
#
|
16
|
+
#
|
17
|
+
# You get an easy-to-read diff output like this:
|
18
|
+
#
|
19
|
+
# 1) Failure:
|
20
|
+
# test_to_gpoints(RouteTest) [test/unit/route_test.rb:29]:
|
21
|
+
# 1c1
|
22
|
+
# < new GPolyline([
|
23
|
+
# ---
|
24
|
+
# > new Gpolyline([
|
25
|
+
#
|
26
|
+
# == Usage
|
27
|
+
#
|
28
|
+
# test.rb | unit_diff [options]
|
29
|
+
# options:
|
30
|
+
# -b ignore whitespace differences
|
31
|
+
# -c contextual diff
|
32
|
+
# -h show usage
|
33
|
+
# -k keep temp diff files around
|
34
|
+
# -l prefix line numbers on the diffs
|
35
|
+
# -u unified diff
|
36
|
+
# -v display version
|
37
|
+
|
38
|
+
class UnitDiff
|
39
|
+
|
40
|
+
WINDOZE = /win32/ =~ RUBY_PLATFORM unless defined? WINDOZE
|
41
|
+
DIFF = if WINDOZE
|
42
|
+
'diff.exe'
|
43
|
+
else
|
44
|
+
if system("gdiff", __FILE__, __FILE__)
|
45
|
+
'gdiff' # solaris and kin suck
|
46
|
+
else
|
47
|
+
'diff'
|
48
|
+
end
|
49
|
+
end unless defined? DIFF
|
50
|
+
|
51
|
+
##
|
52
|
+
# Handy wrapper for UnitDiff#unit_diff.
|
53
|
+
|
54
|
+
def self.unit_diff
|
55
|
+
trap 'INT' do exit 1 end
|
56
|
+
puts UnitDiff.new.unit_diff
|
57
|
+
end
|
58
|
+
|
59
|
+
def parse_input(input, output)
|
60
|
+
current = []
|
61
|
+
data = []
|
62
|
+
data << current
|
63
|
+
print_lines = true
|
64
|
+
|
65
|
+
term = "\nFinished".split(//).map { |c| c[0] }
|
66
|
+
term_length = term.size
|
67
|
+
|
68
|
+
old_sync = output.sync
|
69
|
+
output.sync = true
|
70
|
+
while line = input.gets
|
71
|
+
case line
|
72
|
+
when /^(Loaded suite|Started)/ then
|
73
|
+
print_lines = true
|
74
|
+
output.puts line
|
75
|
+
chars = []
|
76
|
+
while c = input.getc do
|
77
|
+
output.putc c
|
78
|
+
chars << c
|
79
|
+
tail = chars[-term_length..-1]
|
80
|
+
break if chars.size >= term_length and tail == term
|
81
|
+
end
|
82
|
+
output.puts input.gets # the rest of "Finished in..."
|
83
|
+
output.puts
|
84
|
+
next
|
85
|
+
when /^\s*$/, /^\(?\s*\d+\) (Failure|Error):/, /^\d+\)/ then
|
86
|
+
print_lines = false
|
87
|
+
current = []
|
88
|
+
data << current
|
89
|
+
when /^Finished in \d/ then
|
90
|
+
print_lines = false
|
91
|
+
end
|
92
|
+
output.puts line if print_lines
|
93
|
+
current << line
|
94
|
+
end
|
95
|
+
output.sync = old_sync
|
96
|
+
data = data.reject { |o| o == ["\n"] or o.empty? }
|
97
|
+
footer = data.pop
|
98
|
+
|
99
|
+
data.map do |result|
|
100
|
+
break if result.any? { |l| l =~ / expected( but was|, not)/ }
|
101
|
+
|
102
|
+
header = result.find do |l|
|
103
|
+
l =~ /^\(?\s*\d+\) (Failure|Error):/
|
104
|
+
end
|
105
|
+
|
106
|
+
break unless header
|
107
|
+
|
108
|
+
message_index = result.index(header) + 2
|
109
|
+
|
110
|
+
result[message_index..-1] = result[message_index..-1].join
|
111
|
+
end
|
112
|
+
|
113
|
+
return data, footer
|
114
|
+
end
|
115
|
+
|
116
|
+
# Parses a single diff recording the header and what
|
117
|
+
# was expected, and what was actually obtained.
|
118
|
+
def parse_diff(result)
|
119
|
+
header = []
|
120
|
+
expect = []
|
121
|
+
butwas = []
|
122
|
+
footer = []
|
123
|
+
found = false
|
124
|
+
state = :header
|
125
|
+
|
126
|
+
until result.empty? do
|
127
|
+
case state
|
128
|
+
when :header then
|
129
|
+
header << result.shift
|
130
|
+
state = :expect if result.first =~ /^<|^Expected/
|
131
|
+
when :expect then
|
132
|
+
case result.first
|
133
|
+
when /^Expected (.*?) to equal (.*?):$/ then
|
134
|
+
expect << $1
|
135
|
+
butwas << $2
|
136
|
+
state = :footer
|
137
|
+
result.shift
|
138
|
+
when /^Expected (.*?), not (.*)$/m then
|
139
|
+
expect << $1
|
140
|
+
butwas << $2
|
141
|
+
state = :footer
|
142
|
+
result.shift
|
143
|
+
when /^Expected (.*?)$/ then
|
144
|
+
expect << "#{$1}\n"
|
145
|
+
result.shift
|
146
|
+
when /^to equal / then
|
147
|
+
state = :spec_butwas
|
148
|
+
bw = result.shift.sub(/^to equal (.*):?$/, '\1')
|
149
|
+
butwas << bw
|
150
|
+
else
|
151
|
+
state = :butwas if result.first.sub!(/ expected( but was|, not)/, '')
|
152
|
+
expect << result.shift
|
153
|
+
end
|
154
|
+
when :butwas then
|
155
|
+
butwas = result[0..-1]
|
156
|
+
result.clear
|
157
|
+
when :spec_butwas then
|
158
|
+
if result.first =~ /^\s+\S+ at |^:\s*$/
|
159
|
+
state = :footer
|
160
|
+
else
|
161
|
+
butwas << result.shift
|
162
|
+
end
|
163
|
+
when :footer then
|
164
|
+
butwas.last.sub!(/:$/, '')
|
165
|
+
footer = result.map {|l| l.chomp }
|
166
|
+
result.clear
|
167
|
+
else
|
168
|
+
raise "unknown state #{state}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
return header, expect, nil, footer if butwas.empty?
|
173
|
+
|
174
|
+
expect.last.chomp!
|
175
|
+
expect.first.sub!(/^<\"/, '')
|
176
|
+
expect.last.sub!(/\">$/, '')
|
177
|
+
|
178
|
+
butwas.last.chomp!
|
179
|
+
butwas.last.chop! if butwas.last =~ /\.$/
|
180
|
+
butwas.first.sub!( /^<\"/, '')
|
181
|
+
butwas.last.sub!(/\">$/, '')
|
182
|
+
|
183
|
+
return header, expect, butwas, footer
|
184
|
+
end
|
185
|
+
|
186
|
+
##
|
187
|
+
# Scans Test::Unit output +input+ looking for comparison failures and makes
|
188
|
+
# them easily readable by passing them through diff.
|
189
|
+
|
190
|
+
def unit_diff(input=ARGF, output=$stdout)
|
191
|
+
$b = false unless defined? $b
|
192
|
+
$c = false unless defined? $c
|
193
|
+
$k = false unless defined? $k
|
194
|
+
$u = false unless defined? $u
|
195
|
+
|
196
|
+
data, footer = self.parse_input(input, output)
|
197
|
+
|
198
|
+
output = []
|
199
|
+
|
200
|
+
# Output
|
201
|
+
data.each do |result|
|
202
|
+
first = []
|
203
|
+
second = []
|
204
|
+
|
205
|
+
if result.first =~ /Error/ then
|
206
|
+
output.push result.join('')
|
207
|
+
next
|
208
|
+
end
|
209
|
+
|
210
|
+
prefix, expect, butwas, result_footer = parse_diff(result)
|
211
|
+
|
212
|
+
output.push prefix.compact.map {|line| line.strip}.join("\n")
|
213
|
+
|
214
|
+
if butwas then
|
215
|
+
output.push self.diff(expect, butwas)
|
216
|
+
|
217
|
+
output.push result_footer
|
218
|
+
output.push ''
|
219
|
+
else
|
220
|
+
output.push expect.join('')
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
if footer then
|
225
|
+
footer.shift if footer.first.strip.empty?# unless footer.first.nil?
|
226
|
+
output.push footer.compact.map {|line| line.strip}.join("\n")
|
227
|
+
end
|
228
|
+
|
229
|
+
return output.flatten.join("\n")
|
230
|
+
end
|
231
|
+
|
232
|
+
def diff expect, butwas
|
233
|
+
output = nil
|
234
|
+
|
235
|
+
Tempfile.open("expect") do |a|
|
236
|
+
a.write(massage(expect))
|
237
|
+
a.rewind
|
238
|
+
Tempfile.open("butwas") do |b|
|
239
|
+
b.write(massage(butwas))
|
240
|
+
b.rewind
|
241
|
+
|
242
|
+
diff_flags = $u ? "-u" : $c ? "-c" : ""
|
243
|
+
diff_flags += " -b" if $b
|
244
|
+
|
245
|
+
result = `#{DIFF} #{diff_flags} #{a.path} #{b.path}`
|
246
|
+
output = if result.empty? then
|
247
|
+
"[no difference--suspect ==]"
|
248
|
+
else
|
249
|
+
result.split(/\n/)
|
250
|
+
end
|
251
|
+
|
252
|
+
if $k then
|
253
|
+
warn "moving #{a.path} to #{a.path}.keep"
|
254
|
+
File.rename a.path, a.path + ".keep"
|
255
|
+
warn "moving #{b.path} to #{b.path}.keep"
|
256
|
+
File.rename b.path, b.path + ".keep"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
output
|
262
|
+
end
|
263
|
+
|
264
|
+
def massage(data)
|
265
|
+
count = 0
|
266
|
+
# unescape newlines, strip <> from entire string
|
267
|
+
data = data.join
|
268
|
+
data = data.gsub(/\\n/, "\n").gsub(/0x[a-f0-9]+/m, '0xXXXXXX') + "\n"
|
269
|
+
data += "\n" unless data[-1] == ?\n
|
270
|
+
data
|
271
|
+
end
|
272
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,520 @@
|
|
1
|
+
require File.expand_path('test/helper')
|
2
|
+
require 'autotest'
|
3
|
+
|
4
|
+
|
5
|
+
# NOT TESTED:
|
6
|
+
# class_run
|
7
|
+
# add_sigint_handler
|
8
|
+
# all_good
|
9
|
+
# get_to_green
|
10
|
+
# reset
|
11
|
+
# ruby
|
12
|
+
# run
|
13
|
+
# run_tests
|
14
|
+
|
15
|
+
class Autotest
|
16
|
+
attr_reader :test_mappings, :exception_list
|
17
|
+
|
18
|
+
def self.clear_hooks
|
19
|
+
HOOKS.clear
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TestAutotest < Test::Unit::TestCase
|
24
|
+
def refute test, msg=nil
|
25
|
+
if msg then
|
26
|
+
assert ! test, msg
|
27
|
+
else
|
28
|
+
assert ! test
|
29
|
+
end
|
30
|
+
end unless respond_to? :refute
|
31
|
+
alias :deny :refute
|
32
|
+
|
33
|
+
RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']) unless defined? RUBY
|
34
|
+
|
35
|
+
def setup
|
36
|
+
@test_class = 'TestBlah'
|
37
|
+
@test = 'test/test_blah.rb'
|
38
|
+
@other_test = 'test/test_blah_other.rb'
|
39
|
+
@impl = 'lib/blah.rb'
|
40
|
+
@inner_test = 'test/outer/test_inner.rb'
|
41
|
+
@outer_test = 'test/test_outer.rb'
|
42
|
+
@inner_test_class = "TestOuter::TestInner"
|
43
|
+
|
44
|
+
klassname = self.class.name.sub(/^Test/, '')
|
45
|
+
klassname.sub!(/^(\w+)(Autotest)$/, '\2::\1') unless klassname == "Autotest"
|
46
|
+
@a = klassname.split(/::/).inject(Object) { |k,n| k.const_get(n) }.new
|
47
|
+
@a.output = StringIO.new
|
48
|
+
@a.last_mtime = Time.at(2)
|
49
|
+
@a.options[:bundle_exec] = nil
|
50
|
+
@a.options[:parallel] = nil
|
51
|
+
|
52
|
+
@files = {}
|
53
|
+
@files[@impl] = Time.at(1)
|
54
|
+
@files[@test] = Time.at(2)
|
55
|
+
|
56
|
+
@a.find_order = @files.keys.sort
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_add_exception
|
60
|
+
current = util_exceptions
|
61
|
+
@a.add_exception 'blah'
|
62
|
+
|
63
|
+
actual = util_exceptions
|
64
|
+
expect = current + ["blah"]
|
65
|
+
|
66
|
+
assert_equal expect, actual
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_add_mapping
|
70
|
+
current = util_mappings
|
71
|
+
@a.add_mapping(/blah/) do 42 end
|
72
|
+
|
73
|
+
actual = util_mappings
|
74
|
+
expect = current + [/blah/]
|
75
|
+
|
76
|
+
assert_equal expect, actual
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_add_mapping_front
|
80
|
+
current = util_mappings
|
81
|
+
@a.add_mapping(/blah/, :front) do 42 end
|
82
|
+
|
83
|
+
actual = util_mappings
|
84
|
+
expect = [/blah/] + current
|
85
|
+
|
86
|
+
assert_equal expect, actual
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_clear_exceptions
|
90
|
+
test_add_exception
|
91
|
+
@a.clear_exceptions
|
92
|
+
|
93
|
+
actual = util_exceptions
|
94
|
+
expect = []
|
95
|
+
|
96
|
+
assert_equal expect, actual
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_clear_mapping
|
100
|
+
@a.clear_mappings
|
101
|
+
|
102
|
+
actual = util_mappings
|
103
|
+
expect = []
|
104
|
+
|
105
|
+
assert_equal expect, actual
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_consolidate_failures_experiment
|
109
|
+
@files.clear
|
110
|
+
@files[@impl] = Time.at(1)
|
111
|
+
@files[@test] = Time.at(2)
|
112
|
+
|
113
|
+
@a.find_order = @files.keys.sort
|
114
|
+
|
115
|
+
input = [['test_fail1', @test_class],
|
116
|
+
['test_fail2', @test_class],
|
117
|
+
['test_error1', @test_class],
|
118
|
+
['test_error2', @test_class]]
|
119
|
+
result = @a.consolidate_failures input
|
120
|
+
expected = { @test => %w( test_fail1 test_fail2 test_error1 test_error2 ) }
|
121
|
+
assert_equal expected, result
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_consolidate_failures_green
|
125
|
+
result = @a.consolidate_failures([])
|
126
|
+
expected = {}
|
127
|
+
assert_equal expected, result
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_consolidate_failures_multiple_possibilities
|
131
|
+
@files[@other_test] = Time.at(42)
|
132
|
+
result = @a.consolidate_failures([['test_unmatched', @test_class]])
|
133
|
+
expected = { @test => ['test_unmatched']}
|
134
|
+
assert_equal expected, result
|
135
|
+
expected = ""
|
136
|
+
assert_equal expected, @a.output.string
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_consolidate_failures_nested_classes
|
140
|
+
@files.clear
|
141
|
+
@files['lib/outer.rb'] = Time.at(5)
|
142
|
+
@files['lib/outer/inner.rb'] = Time.at(5)
|
143
|
+
@files[@inner_test] = Time.at(5)
|
144
|
+
@files[@outer_test] = Time.at(5)
|
145
|
+
|
146
|
+
@a.find_order = @files.keys.sort
|
147
|
+
|
148
|
+
result = @a.consolidate_failures([['test_blah1', @inner_test_class]])
|
149
|
+
expected = { @inner_test => ['test_blah1'] }
|
150
|
+
assert_equal expected, result
|
151
|
+
expected = ""
|
152
|
+
assert_equal expected, @a.output.string
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_consolidate_failures_no_match
|
156
|
+
result = @a.consolidate_failures([['test_blah1', @test_class], ['test_blah2', @test_class], ['test_blah1', 'TestUnknown']])
|
157
|
+
expected = {@test => ['test_blah1', 'test_blah2']}
|
158
|
+
assert_equal expected, result
|
159
|
+
expected = "Unable to map class TestUnknown to a file\n"
|
160
|
+
assert_equal expected, @a.output.string
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_consolidate_failures_red
|
164
|
+
result = @a.consolidate_failures([['test_blah1', @test_class], ['test_blah2', @test_class]])
|
165
|
+
expected = {@test => ['test_blah1', 'test_blah2']}
|
166
|
+
assert_equal expected, result
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_exceptions
|
170
|
+
@a.clear_exceptions
|
171
|
+
test_add_exception
|
172
|
+
assert_equal(/blah/, @a.exceptions)
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_exceptions_nil
|
176
|
+
@a.clear_exceptions
|
177
|
+
assert_nil @a.exceptions
|
178
|
+
end
|
179
|
+
|
180
|
+
# TODO: lots of filename edgecases for find_files_to_test
|
181
|
+
def test_find_files_to_test
|
182
|
+
@a.last_mtime = Time.at(0)
|
183
|
+
assert @a.find_files_to_test(@files)
|
184
|
+
|
185
|
+
@a.last_mtime = @files.values.sort.last + 1
|
186
|
+
deny @a.find_files_to_test(@files)
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_find_files_to_test_dunno
|
190
|
+
empty = {}
|
191
|
+
|
192
|
+
files = { "fooby.rb" => Time.at(42) }
|
193
|
+
assert @a.find_files_to_test(files) # we find fooby,
|
194
|
+
assert_equal empty, @a.files_to_test # but it isn't something to test
|
195
|
+
assert_equal "No tests matched fooby.rb\n", @a.output.string
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_find_files_to_test_lib
|
199
|
+
# ensure we add test_blah.rb when blah.rb updates
|
200
|
+
util_find_files_to_test(@impl, @test => [])
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_find_files_to_test_no_change
|
204
|
+
empty = {}
|
205
|
+
|
206
|
+
# ensure world is virginal
|
207
|
+
assert_equal empty, @a.files_to_test
|
208
|
+
|
209
|
+
# ensure we do nothing when nothing changes...
|
210
|
+
files = { @impl => @files[@impl] } # same time
|
211
|
+
deny @a.find_files_to_test(files)
|
212
|
+
assert_equal empty, @a.files_to_test
|
213
|
+
assert_equal "", @a.output.string
|
214
|
+
|
215
|
+
files = { @impl => @files[@impl] } # same time
|
216
|
+
assert(! @a.find_files_to_test(files))
|
217
|
+
assert_equal empty, @a.files_to_test
|
218
|
+
assert_equal "", @a.output.string
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_find_files_to_test_test
|
222
|
+
# ensure we add test_blah.rb when test_blah.rb itself updates
|
223
|
+
util_find_files_to_test(@test, @test => [])
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_reorder_alpha
|
227
|
+
@a.order = :alpha
|
228
|
+
expected = @files.sort
|
229
|
+
|
230
|
+
assert_equal expected, @a.reorder(@files)
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_reorder_reverse
|
234
|
+
@a.order = :reverse
|
235
|
+
expected = @files.sort.reverse
|
236
|
+
|
237
|
+
assert_equal expected, @a.reorder(@files)
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_reorder_random
|
241
|
+
@a.order = :random
|
242
|
+
|
243
|
+
srand 42
|
244
|
+
expected, size = @files.dup, @files.size
|
245
|
+
expected = expected.sort_by { rand(size) }
|
246
|
+
|
247
|
+
srand 42
|
248
|
+
result = @a.reorder(@files.dup)
|
249
|
+
|
250
|
+
assert_equal expected, result
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_reorder_natural
|
254
|
+
srand 42
|
255
|
+
|
256
|
+
@files['lib/untested_blah.rb'] = Time.at(2)
|
257
|
+
@a.find_order = @files.keys.sort_by { rand }
|
258
|
+
|
259
|
+
@a.order = :natural
|
260
|
+
expected = @a.find_order.map { |f| [f, @files[f]] }
|
261
|
+
|
262
|
+
assert_equal expected, @a.reorder(@files)
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_handle_results
|
266
|
+
@a.files_to_test.clear
|
267
|
+
@files.clear
|
268
|
+
@files[@impl] = Time.at(1)
|
269
|
+
@files[@test] = Time.at(2)
|
270
|
+
|
271
|
+
@a.find_order = @files.keys.sort
|
272
|
+
|
273
|
+
empty = {}
|
274
|
+
assert_equal empty, @a.files_to_test, "must start empty"
|
275
|
+
|
276
|
+
s1 = "Loaded suite -e
|
277
|
+
Started
|
278
|
+
............
|
279
|
+
Finished in 0.001655 seconds.
|
280
|
+
|
281
|
+
12 tests, 18 assertions, 0 failures, 0 errors
|
282
|
+
"
|
283
|
+
|
284
|
+
@a.handle_results(s1)
|
285
|
+
assert_equal empty, @a.files_to_test, "must stay empty"
|
286
|
+
|
287
|
+
exp = { "tests" => 12, "assertions" => 18, "failures" => 0, "errors" => 0 }
|
288
|
+
assert_equal exp, @a.latest_results
|
289
|
+
|
290
|
+
s2 = "
|
291
|
+
1) Failure:
|
292
|
+
test_fail1(#{@test_class}) [#{@test}:59]:
|
293
|
+
2) Failure:
|
294
|
+
test_fail2(#{@test_class}) [#{@test}:60]:
|
295
|
+
3) Error:
|
296
|
+
test_error1(#{@test_class}):
|
297
|
+
3) Error:
|
298
|
+
test_error2(#{@test_class}):
|
299
|
+
|
300
|
+
12 tests, 18 assertions, 2 failures, 2 errors
|
301
|
+
"
|
302
|
+
|
303
|
+
@a.handle_results(s2)
|
304
|
+
expected = { @test => %w( test_fail1 test_fail2 test_error1 test_error2 ) }
|
305
|
+
assert_equal expected, @a.files_to_test
|
306
|
+
assert @a.tainted
|
307
|
+
exp = { "tests" => 12, "assertions" => 18, "failures" => 2, "errors" => 2 }
|
308
|
+
assert_equal exp, @a.latest_results
|
309
|
+
|
310
|
+
@a.handle_results(s1)
|
311
|
+
assert_equal empty, @a.files_to_test
|
312
|
+
|
313
|
+
s3 = '
|
314
|
+
/opt/bin/ruby -I.:lib:test -rubygems -e "%w[test/unit #{@test}].each { |f| require f }" | unit_diff -u
|
315
|
+
-e:1:in `require\': ./#{@test}:23: parse error, unexpected tIDENTIFIER, expecting \'}\' (SyntaxError)
|
316
|
+
settings_fields.each {|e| assert_equal e, version.send e.intern}
|
317
|
+
^ from -e:1
|
318
|
+
from -e:1:in `each\'
|
319
|
+
from -e:1
|
320
|
+
'
|
321
|
+
@a.files_to_test[@test] = Time.at(42)
|
322
|
+
@files[@test] = []
|
323
|
+
expected = { @test => Time.at(42) }
|
324
|
+
assert_equal expected, @a.files_to_test
|
325
|
+
@a.handle_results(s3)
|
326
|
+
assert_equal expected, @a.files_to_test
|
327
|
+
assert @a.tainted
|
328
|
+
@a.tainted = false
|
329
|
+
|
330
|
+
@a.handle_results(s1)
|
331
|
+
assert_equal empty, @a.files_to_test
|
332
|
+
deny @a.tainted
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_hook_overlap_returning_false
|
336
|
+
util_reset_hooks_returning false
|
337
|
+
|
338
|
+
@a.hook :blah
|
339
|
+
|
340
|
+
assert @a.instance_variable_get(:@blah1), "Hook1 should work on blah"
|
341
|
+
assert @a.instance_variable_get(:@blah2), "Hook2 should work on blah"
|
342
|
+
assert @a.instance_variable_get(:@blah3), "Hook3 should work on blah"
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_hook_overlap_returning_true
|
346
|
+
util_reset_hooks_returning true
|
347
|
+
|
348
|
+
@a.hook :blah
|
349
|
+
|
350
|
+
assert @a.instance_variable_get(:@blah1), "Hook1 should work on blah"
|
351
|
+
deny @a.instance_variable_get(:@blah2), "Hook2 should NOT work on blah"
|
352
|
+
deny @a.instance_variable_get(:@blah3), "Hook3 should NOT work on blah"
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_hook_response
|
356
|
+
Autotest.clear_hooks
|
357
|
+
deny @a.hook(:blah)
|
358
|
+
|
359
|
+
Autotest.add_hook(:blah) { false }
|
360
|
+
deny @a.hook(:blah)
|
361
|
+
|
362
|
+
Autotest.add_hook(:blah) { false }
|
363
|
+
deny @a.hook(:blah)
|
364
|
+
|
365
|
+
Autotest.add_hook(:blah) { true }
|
366
|
+
assert @a.hook(:blah)
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_make_test_cmd_basics
|
370
|
+
f = {
|
371
|
+
@test => [],
|
372
|
+
'test/test_fooby.rb' => [ 'test_something1', 'test_something2' ]
|
373
|
+
}
|
374
|
+
|
375
|
+
unit_diff = "ruby #{File.expand_path("#{File.dirname(__FILE__)}/../bin/unit_diff")}"
|
376
|
+
pre = "#{RUBY} -I.:lib:test -rubygems"
|
377
|
+
req = ".each { |f| require f }\""
|
378
|
+
post = "| #{unit_diff} -u"
|
379
|
+
|
380
|
+
expected = [
|
381
|
+
"#{pre} -e \"['test/unit', '#{@test}']#{req} #{post}",
|
382
|
+
"#{pre} test/test_fooby.rb -n \"/^(test_something1|test_something2)$/\" #{post}"
|
383
|
+
].join("; ")
|
384
|
+
|
385
|
+
result = @a.make_test_cmd f
|
386
|
+
assert_equal expected, result
|
387
|
+
end
|
388
|
+
|
389
|
+
def test_make_test_cmd_uses_bundle_exec_when_given
|
390
|
+
@a.prefix = 'bundle exec '
|
391
|
+
f = {
|
392
|
+
@test => []
|
393
|
+
}
|
394
|
+
result = @a.make_test_cmd f
|
395
|
+
assert_match /^bundle exec \//,result
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_make_test_cmd_uses_prefix_with_parallel_test
|
399
|
+
@a.prefix = 'bundle exec '
|
400
|
+
@a.options[:parallel] = true
|
401
|
+
f = {
|
402
|
+
'test/a.rb' => [],
|
403
|
+
'test/b.rb' => []
|
404
|
+
}
|
405
|
+
result = @a.make_test_cmd f
|
406
|
+
assert_match /^bundle exec parallel_test/, result
|
407
|
+
end
|
408
|
+
|
409
|
+
def test_make_test_cmd_uses_parallel_with_multiple_files
|
410
|
+
@a.options[:parallel] = true
|
411
|
+
f = {
|
412
|
+
'test/a.rb' => [],
|
413
|
+
'test/b.rb' => []
|
414
|
+
}
|
415
|
+
result = @a.make_test_cmd f
|
416
|
+
assert_match /^parallel_test/, result
|
417
|
+
end
|
418
|
+
|
419
|
+
def test_make_test_cmd_does_not_use_parallel_for_single_file
|
420
|
+
@a.options[:parallel] = true
|
421
|
+
f = {
|
422
|
+
'test/a.rb' => []
|
423
|
+
}
|
424
|
+
result = @a.make_test_cmd f
|
425
|
+
assert_equal nil, (/^parallel_test/ =~ result)
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_path_to_classname
|
429
|
+
# non-rails
|
430
|
+
util_path_to_classname 'TestBlah', 'test/test_blah.rb'
|
431
|
+
util_path_to_classname 'TestOuter::TestInner', 'test/outer/test_inner.rb'
|
432
|
+
util_path_to_classname 'TestRuby2Ruby', 'test/test_ruby2ruby.rb'
|
433
|
+
end
|
434
|
+
|
435
|
+
def test_remove_exception
|
436
|
+
test_add_exception
|
437
|
+
current = util_exceptions
|
438
|
+
@a.remove_exception 'blah'
|
439
|
+
|
440
|
+
actual = util_exceptions
|
441
|
+
expect = current - ["blah"]
|
442
|
+
|
443
|
+
assert_equal expect, actual
|
444
|
+
end
|
445
|
+
|
446
|
+
def test_remove_mapping
|
447
|
+
current = util_mappings
|
448
|
+
@a.remove_mapping(/^lib\/.*\.rb$/)
|
449
|
+
|
450
|
+
actual = util_mappings
|
451
|
+
expect = current - [/^lib\/.*\.rb$/]
|
452
|
+
|
453
|
+
assert_equal expect, actual
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_test_files_for
|
457
|
+
assert_equal [@test], @a.test_files_for(@impl)
|
458
|
+
assert_equal [@test], @a.test_files_for(@test)
|
459
|
+
|
460
|
+
assert_equal [], @a.test_files_for('test/test_unknown.rb')
|
461
|
+
assert_equal [], @a.test_files_for('lib/unknown.rb')
|
462
|
+
assert_equal [], @a.test_files_for('unknown.rb')
|
463
|
+
assert_equal [], @a.test_files_for('test_unknown.rb')
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_testlib
|
467
|
+
assert_equal "test/unit", @a.testlib
|
468
|
+
|
469
|
+
@a.testlib = "MONKEY"
|
470
|
+
assert_equal "MONKEY", @a.testlib
|
471
|
+
|
472
|
+
f = { @test => [], "test/test_fooby.rb" => %w(first second) }
|
473
|
+
assert_match @a.testlib, @a.make_test_cmd(f)
|
474
|
+
end
|
475
|
+
|
476
|
+
def util_exceptions
|
477
|
+
@a.exception_list.sort_by { |r| r.to_s }
|
478
|
+
end
|
479
|
+
|
480
|
+
def util_find_files_to_test(f, expected)
|
481
|
+
t = @a.last_mtime
|
482
|
+
files = { f => t + 1 }
|
483
|
+
|
484
|
+
assert @a.find_files_to_test(files)
|
485
|
+
assert_equal expected, @a.files_to_test
|
486
|
+
assert_equal t, @a.last_mtime
|
487
|
+
assert_equal "", @a.output.string
|
488
|
+
end
|
489
|
+
|
490
|
+
def util_mappings
|
491
|
+
@a.test_mappings.map { |k,v| k }
|
492
|
+
end
|
493
|
+
|
494
|
+
def util_path_to_classname(e,i)
|
495
|
+
assert_equal e, @a.path_to_classname(i)
|
496
|
+
end
|
497
|
+
|
498
|
+
def util_reset_hooks_returning val
|
499
|
+
Autotest.clear_hooks
|
500
|
+
|
501
|
+
@a.instance_variable_set :@blah1, false
|
502
|
+
@a.instance_variable_set :@blah2, false
|
503
|
+
@a.instance_variable_set :@blah3, false
|
504
|
+
|
505
|
+
Autotest.add_hook(:blah) do |at|
|
506
|
+
at.instance_variable_set :@blah1, true
|
507
|
+
val
|
508
|
+
end
|
509
|
+
|
510
|
+
Autotest.add_hook(:blah) do |at|
|
511
|
+
at.instance_variable_set :@blah2, true
|
512
|
+
val
|
513
|
+
end
|
514
|
+
|
515
|
+
Autotest.add_hook(:blah) do |at|
|
516
|
+
at.instance_variable_set :@blah3, true
|
517
|
+
val
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|