4 # Never use optparse in this file.
5 # Never use test/unit in this file.
6 # Never use Ruby extensions in this file.
12 $:.unshift File.join(File.dirname(__FILE__), '../lib')
16 if !Dir.respond_to?(:mktmpdir)
17 # copied from lib/tmpdir.rb
18 def Dir.mktmpdir(prefix="d", tmpdir=nil)
20 t = Time.now.strftime("%Y%m%d")
23 path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}"
36 FileUtils.remove_entry_secure path
45 @ruby = File.expand_path('miniruby')
54 @ruby.gsub!(/^([^ ]*)/){File.expand_path($1)}
55 @ruby.gsub!(/(\s+-I\s*)((?!(?:\.\/)*-(?:\s|\z))\S+)/){$1+File.expand_path($2)}
56 @ruby.gsub!(/(\s+-r\s*)(\.\.?\/\S+)/){$1+File.expand_path($2)}
59 tests = Dir.glob("#{File.dirname($0)}/test_{#{$1}}*.rb")
60 puts tests.map {|path| File.basename(path) }.inspect
65 when /\A(--stress|-s)/
67 when /\A(-q|--q(uiet))\z/
70 when /\A(-v|--v(erbose))\z/
72 when /\A(-h|--h(elp)?)\z/
74 Usage: #{File.basename($0, '.*')} --ruby=PATH [--sets=NAME,NAME,...]
75 --sets=NAME,NAME,... Name of test sets.
76 --dir=DIRECTORY Working directory.
77 default: /tmp/bootstraptest.tmpwd
78 -s, --stress stress test.
79 -v, --verbose Output test name before exec.
80 -q, --quiet Don\'t print header message.
81 -h, --help Print this message and quit.
88 if tests and not ARGV.empty?
89 $stderr.puts "--tests and arguments are exclusive"
93 tests = Dir.glob("#{File.dirname($0)}/test_*.rb") if tests.empty?
94 pathes = tests.map {|path| File.expand_path(path) }
98 patchlevel = defined?(RUBY_PATCHLEVEL) ? " patchlevel #{RUBY_PATCHLEVEL}" : ''
99 puts "Driver is ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}#{patchlevel}) [#{RUBY_PLATFORM}]"
100 puts "Target is #{`#{@ruby} -v`.chomp}"
105 in_temporary_working_directory(dir) {
110 def exec_test(pathes)
115 pathes.each do |path|
116 $stderr.print "\n#{File.basename(path)} "
117 load File.expand_path(path)
121 $stderr.puts "PASS #{@count} tests"
124 @errbuf.each do |msg|
127 $stderr.puts "FAIL #{@error}/#{@count} tests failed"
132 def assert_check(testsrc, message = '', opt = '')
133 $stderr.puts "\##{@count} #{@location}" if @verbose
134 result = get_result_string(testsrc, opt)
136 faildesc = yield(result)
141 error faildesc, message
143 rescue Exception => err
145 error err.message, message
148 def assert_equal(expected, testsrc, message = '')
150 assert_check(testsrc, message) {|result|
151 if expected == result
154 desc = "#{result.inspect} (expected #{expected.inspect})"
155 pretty(testsrc, desc, result)
160 def assert_match(expected_pattern, testsrc, message = '')
162 assert_check(testsrc, message) {|result|
163 if expected_pattern =~ result
166 desc = "#{expected_pattern.inspect} expected to be =~\n#{result.inspect}"
167 pretty(testsrc, desc, result)
172 def assert_not_match(unexpected_pattern, testsrc, message = '')
174 assert_check(testsrc, message) {|result|
175 if unexpected_pattern !~ result
178 desc = "#{unexpected_pattern.inspect} expected to be !~\n#{result.inspect}"
179 pretty(testsrc, desc, result)
184 def assert_valid_syntax(testsrc, message = '')
186 assert_check(testsrc, message, '-c') {|result|
187 result if /Syntax OK/ !~ result
191 def assert_normal_exit(testsrc, message = '', ignore_signals = nil)
193 $stderr.puts "\##{@count} #{@location}" if @verbose
195 filename = make_srcfile(testsrc)
196 old_stderr = $stderr.dup
198 $stderr.reopen("assert_normal_exit_stderr.log", "w")
199 `#{@ruby} -W0 #{filename}`
202 $stderr.reopen(old_stderr)
206 signo = status.termsig
207 signame = Signal.list.invert[signo]
208 unless ignore_signals and ignore_signals.include?(signame)
209 sigdesc = "signal #{signo}"
211 sigdesc = "SIG#{signame} (#{sigdesc})"
213 faildesc = pretty(testsrc, "killed by #{sigdesc}", nil)
214 stderr_log = File.read("assert_normal_exit_stderr.log")
215 if !stderr_log.empty?
216 faildesc << "\n" if /\n\z/ !~ faildesc
217 stderr_log << "\n" if /\n\z/ !~ stderr_log
218 stderr_log.gsub!(/^.*\n/) { '| ' + $& }
219 faildesc << stderr_log
228 error faildesc, message
231 rescue Exception => err
233 error err.message, message
237 def assert_finish(timeout_seconds, testsrc, message = '')
239 $stderr.puts "\##{@count} #{@location}" if @verbose
241 filename = make_srcfile(testsrc)
242 io = IO.popen("#{@ruby} -W0 #{filename}")
245 tlimit = Time.now + timeout_seconds
246 while Time.now < tlimit
247 if Process.waitpid pid, Process::WNOHANG
254 Process.kill(:KILL, pid)
256 faildesc = pretty(testsrc, "not finished in #{timeout_seconds} seconds", nil)
263 error faildesc, message
265 rescue Exception => err
267 error err.message, message
270 def flunk(message = '')
276 def pretty(src, desc, result)
277 src = src.sub(/\A.*\n/, '')
278 (/\n/ =~ src ? "\n#{adjust_indent(src)}" : src) + " #=> #{desc}"
283 def adjust_indent(src)
284 untabify(src).gsub(/^ {#{INDENT}}/o, '').gsub(/^/, ' ')
288 str.gsub(/^\t+/) {' ' * (8 * $&.size) }
291 def make_srcfile(src)
292 filename = 'bootstraptest.tmp.rb'
293 File.open(filename, 'w') {|f|
294 f.puts "GC.stress = true" if $stress
295 f.puts "print(begin; #{src}; end)"
300 def get_result_string(src, opt = '')
302 filename = make_srcfile(src)
304 `#{@ruby} -W0 #{opt} #{filename}`
306 raise CoreDumpError, "core dumped" if $? and $?.coredump?
314 @location = File.basename(caller(2).first)
319 def error(msg, additional_message)
320 @errbuf.push "\##{@count} #{@location}: #{msg} #{additional_message}"
324 def in_temporary_working_directory(dir)
331 Dir.mktmpdir("bootstraptest.tmpwd") {|d|
340 FileUtils.rm_f 'core'
341 FileUtils.rm_f Dir.glob('core.*')
342 FileUtils.rm_f @ruby+'.stackdump' if @ruby
345 class CoreDumpError < StandardError; end
348 if File.file?('core') or not Dir.glob('core.*').empty? or
349 (@ruby and File.exist?(@ruby+'.stackdump'))
350 raise CoreDumpError, "core dumped"