1
"exec" "${RUBY-ruby}" "-x" "$0" "$@"; true # -*- mode: ruby; coding: utf-8 -*-
3
# $Id: runner.rb 32088 2011-06-14 14:17:42Z akr $
6
# Never use optparse in this file.
7
# Never use test/unit in this file.
8
# Never use Ruby extensions in this file.
14
$:.unshift File.join(File.dirname(__FILE__), '../lib')
18
if !Dir.respond_to?(:mktmpdir)
19
# copied from lib/tmpdir.rb
20
def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil)
26
prefix = prefix_suffix
29
prefix = prefix_suffix[0]
30
suffix = prefix_suffix[1]
32
raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}"
35
t = Time.now.strftime("%Y%m%d")
38
path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
52
FileUtils.remove_entry_secure path
61
@ruby = File.expand_path('miniruby')
71
@ruby.gsub!(/^([^ ]*)/){File.expand_path($1)}
72
@ruby.gsub!(/(\s+-I\s*)((?!(?:\.\/)*-(?:\s|\z))\S+)/){$1+File.expand_path($2)}
73
@ruby.gsub!(/(\s+-r\s*)(\.\.?\/\S+)/){$1+File.expand_path($2)}
76
tests = Dir.glob("#{File.dirname($0)}/test_{#{$1}}*.rb").sort
77
puts tests.map {|path| File.basename(path) }.inspect
82
when /\A(--stress|-s)/
84
when /\A(-q|--q(uiet))\z/
87
when /\A(-v|--v(erbose))\z/
89
when /\A(-h|--h(elp)?)\z/
91
Usage: #{File.basename($0, '.*')} --ruby=PATH [--sets=NAME,NAME,...]
92
--sets=NAME,NAME,... Name of test sets.
93
--dir=DIRECTORY Working directory.
94
default: /tmp/bootstraptestXXXXX.tmpwd
95
-s, --stress stress test.
96
-v, --verbose Output test name before exec.
97
-q, --quiet Don\'t print header message.
98
-h, --help Print this message and quit.
105
if tests and not ARGV.empty?
106
$stderr.puts "--tests and arguments are exclusive"
110
tests = Dir.glob("#{File.dirname($0)}/test_*.rb").sort if tests.empty?
111
pathes = tests.map {|path| File.expand_path(path) }
115
if defined?(RUBY_DESCRIPTION)
116
puts "Driver is #{RUBY_DESCRIPTION}"
117
elsif defined?(RUBY_PATCHLEVEL)
118
puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{RUBY_PLATFORM}) [#{RUBY_PLATFORM}]"
120
puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
122
puts "Target is #{`#{@ruby} -v`.chomp}"
127
in_temporary_working_directory(dir) {
132
def exec_test(pathes)
137
pathes.each do |path|
138
$stderr.print "\n#{File.basename(path)} "
139
$stderr.puts if @verbose
140
load File.expand_path(path)
145
$stderr.puts "No tests, no problem"
147
$stderr.puts "PASS all #{@count} tests"
151
@errbuf.each do |msg|
154
$stderr.puts "FAIL #{@error}/#{@count} tests failed"
159
def show_progress(message = '')
161
$stderr.print "\##{@count} #{@location} "
166
$stderr.puts if @verbose
169
$stderr.puts if @verbose
170
error faildesc, message
172
rescue Exception => err
174
$stderr.puts if @verbose
175
error err.message, message
178
def assert_check(testsrc, message = '', opt = '')
179
show_progress(message) {
180
result = get_result_string(testsrc, opt)
186
def assert_equal(expected, testsrc, message = '')
188
assert_check(testsrc, message) {|result|
189
if expected == result
192
desc = "#{result.inspect} (expected #{expected.inspect})"
193
pretty(testsrc, desc, result)
198
def assert_match(expected_pattern, testsrc, message = '')
200
assert_check(testsrc, message) {|result|
201
if expected_pattern =~ result
204
desc = "#{expected_pattern.inspect} expected to be =~\n#{result.inspect}"
205
pretty(testsrc, desc, result)
210
def assert_not_match(unexpected_pattern, testsrc, message = '')
212
assert_check(testsrc, message) {|result|
213
if unexpected_pattern !~ result
216
desc = "#{unexpected_pattern.inspect} expected to be !~\n#{result.inspect}"
217
pretty(testsrc, desc, result)
222
def assert_valid_syntax(testsrc, message = '')
224
assert_check(testsrc, message, '-c') {|result|
225
result if /Syntax OK/ !~ result
229
def assert_normal_exit(testsrc, *rest)
232
opt = rest.pop if Hash === rest.last
233
message, ignore_signals = rest
235
timeout = opt[:timeout]
236
show_progress(message) {
238
filename = make_srcfile(testsrc)
239
old_stderr = $stderr.dup
240
timeout_signaled = false
242
$stderr.reopen("assert_normal_exit.log", "w")
243
io = IO.popen("#{@ruby} -W0 #{filename}")
251
Process.kill :KILL, pid
252
timeout_signaled = true
256
$stderr.reopen(old_stderr)
260
signo = status.termsig
261
signame = Signal.list.invert[signo]
262
unless ignore_signals and ignore_signals.include?(signame)
263
sigdesc = "signal #{signo}"
265
sigdesc = "SIG#{signame} (#{sigdesc})"
268
sigdesc << " (timeout)"
270
faildesc = pretty(testsrc, "killed by #{sigdesc}", nil)
271
stderr_log = File.read("assert_normal_exit.log")
272
if !stderr_log.empty?
273
faildesc << "\n" if /\n\z/ !~ faildesc
274
stderr_log << "\n" if /\n\z/ !~ stderr_log
275
stderr_log.gsub!(/^.*\n/) { '| ' + $& }
276
faildesc << stderr_log
284
def assert_finish(timeout_seconds, testsrc, message = '')
286
show_progress(message) {
288
filename = make_srcfile(testsrc)
289
io = IO.popen("#{@ruby} -W0 #{filename}")
292
tlimit = Time.now + timeout_seconds
293
while Time.now < tlimit
294
if Process.waitpid pid, Process::WNOHANG
301
Process.kill(:KILL, pid)
303
faildesc = pretty(testsrc, "not finished in #{timeout_seconds} seconds", nil)
310
def flunk(message = '')
312
show_progress('') { message }
315
def pretty(src, desc, result)
316
src = src.sub(/\A.*\n/, '')
317
(/\n/ =~ src ? "\n#{adjust_indent(src)}" : src) + " #=> #{desc}"
322
def adjust_indent(src)
323
untabify(src).gsub(/^ {#{INDENT}}/o, '').gsub(/^/, ' ')
327
str.gsub(/^\t+/) {' ' * (8 * $&.size) }
330
def make_srcfile(src)
331
filename = 'bootstraptest.tmp.rb'
332
File.open(filename, 'w') {|f|
333
f.puts "GC.stress = true" if $stress
334
f.puts "print(begin; #{src}; end)"
339
def get_result_string(src, opt = '')
341
filename = make_srcfile(src)
343
`#{@ruby} -W0 #{opt} #{filename}`
345
raise CoreDumpError, "core dumped" if $? and $?.coredump?
353
@location = File.basename(caller(2).first)
358
def error(msg, additional_message)
359
@errbuf.push "\##{@count} #{@location}: #{msg} #{additional_message}"
363
def in_temporary_working_directory(dir)
370
Dir.mktmpdir(["bootstraptest", ".tmpwd"]) {|d|
379
FileUtils.rm_f 'core'
380
FileUtils.rm_f Dir.glob('core.*')
381
FileUtils.rm_f @ruby+'.stackdump' if @ruby
384
class CoreDumpError < StandardError; end
387
if File.file?('core') or not Dir.glob('core.*').empty? or
388
(@ruby and File.exist?(@ruby+'.stackdump'))
389
raise CoreDumpError, "core dumped"