cmdtest/run-regression.rb
2012-08-13 19:02:28 +02:00

363 lines
8.1 KiB
Ruby
Executable File

#!/usr/local/bin/ruby
#----------------------------------------------------------------------
# run-regression.rb
#----------------------------------------------------------------------
# Copyright (c) 2007-2012 by Johan Holmberg. All rights reserved.
#----------------------------------------------------------------------
# @(#) $Id$
#----------------------------------------------------------------------
require "rbconfig"
require "dbm"
require "digest/md5"
#----------------------------------------------------------------------
TMPFILES = [
"tmp-cmdtest-2",
"tmp-cmdtest-2/tmp-command.sh",
"tmp-cmdtest-2/tmp-stderr.log",
"tmp-cmdtest-2/tmp-stdout.log",
"tmp-cmdtest-2/workdir",
"tmp-cmdtest-2/workdir/TIMESTAMP"
]
class ActualTcRegression
def initialize
@count = 0
@f = File.open("TC_actual-regression.rb", "w")
@f.puts [
"class TC_cmdtest < Cmdtest::Testcase",
"",
" def setup",
TMPFILES.map {|file| " ignore_file #{file.inspect}" },
" end",
"",
]
end
def _list_elements(level, lines)
lines.map do |line|
" " * level + line.inspect + ","
end
end
def _indent(level, lines)
lines.map do |line|
" " * level + line
end
end
def _gen_count
@count += 1
end
def _comment_str(lines)
lines.each do |line|
if line =~ /^#/ # ..
res = line.sub(/^#\s*/, "")
return res
end
end
return "no comment given"
end
def add(prefix, code, stdout)
@f.puts [
" def test_#{_gen_count}",
" create_file \"TC_tmp.rb\", [",
" 'class TC_cmdtest < Cmdtest::Testcase',",
" ' def test_foo',",
_list_elements(3, _indent(2, prefix)),
_list_elements(3, _indent(2, code)),
" ' end',",
" 'end',",
" ]",
"",
" cmd 'cmdtest.rb --quiet' do",
" comment #{_comment_str(code).inspect}",
" stdout_equal [",
_list_elements(4, stdout),
" ]",
" end",
" end",
"",
].flatten
end
def write
@f.puts [
"",
"end",
"",
]
@f.close
end
end
#----------------------------------------------------------------------
class ActualRegression
def initialize
@o2 = ActualTcRegression.new
@f = File.open("actual-regression.rb", "w")
end
def add(prefix, code, stdout)
prefix = prefix.map {|line| line.chomp }
code = code .map {|line| line.chomp }
stdout = stdout.map {|line| line.to_s.chomp }
@o2.add(prefix,code,stdout)
@f.puts prefix
@f.puts "#" + "-" * 35
@f.puts code
@f.puts "# stdout begin"
@f.puts stdout.map {|line| "# %s" % [line] }
@f.puts "# stdout end"
end
def write
@o2.write
@f.close
end
end
#----------------------------------------------------------------------
class RegressionData
def initialize(files)
@lines = files.map {|file| File.readlines(file) }.flatten
@i = 0
end
def eof?
j = @i
while j < @lines.size && @lines[j].strip.empty?
j += 1
end
return j >= @lines.size
end
def skip_to(pattern)
# ignore return value
get_to(pattern)
end
def _show_line(i)
puts "%d: %s" % [
i,
@lines[i],
]
end
def get_to(pattern)
res = []
i1 = @i
while ! eof? && @lines[@i] !~ pattern
_show_line(@i) if $opt_verbose
res << @lines[@i]
@i += 1
end
if eof?
puts "Error: looking at:"
_show_line(i1)
raise "eof looking for #{pattern}"
end
# get past matching line
@i += 1
return res
end
end
#----------------------------------------------------------------------
SystemResult = Struct.new(:status, :stdout, :stderr)
def my_system(cmd)
full_cmd = "#{cmd} > tmp-stdout 2> tmp-stderr"
#puts "+ #{full_cmd}"
ok = system full_cmd
status = $?.exitstatus
stdout = File.readlines("tmp-stdout")
stderr = File.readlines("tmp-stderr")
if status != 0
puts "INTERNAL ERROR:"
puts "STDOUT:"
puts stdout
puts "STDERR:"
puts stderr
exit 1
end
#p [:my_system, cmd, status, stdout, stderr]
return SystemResult.new(status, stdout, stderr)
end
#----------------------------------------------------------------------
def indented(lines)
lines.map {|line| " " + line.to_s }
end
#----------------------------------------------------------------------
def indent_lines(level, lines)
lines.map do |line|
" " * level + line
end
end
#----------------------------------------------------------------------
def matching_arrays(a,b)
return false if a.size != b.size
a.each_index do |i|
return false unless a[i] === b[i]
end
return true
end
#----------------------------------------------------------------------
$opt_verbose = false
$opt_only = nil
$opt_remember = false
while /^-/ =~ ARGV[0]
arg = ARGV.shift
case arg
when "-v"
$opt_verbose = true
when "-r"
$opt_remember = true
when /^--only=(\d+)$/
$opt_only = $1.to_i
else
puts "Error: unknown option: #{arg}"
exit 1
end
end
path_dirs = [ File.expand_path("t/bin") ]
if RUBY_PLATFORM =~ /mswin/
path_dirs.unshift File.expand_path("t/bin/windows")
else
path_dirs.unshift File.expand_path("t/bin/unix")
end
ENV["PATH"] = [
path_dirs,
ENV["PATH"]
].join(Config::CONFIG["PATH_SEPARATOR"])
files = ARGV.empty? ? Dir.glob("t/*.rb") : ARGV
rd = RegressionData.new(files)
tests = []
while ! rd.eof?
prefix = rd.get_to( /^#----------/ )
code = rd.get_to( /^# stdout begin/ )
stdout = rd.get_to( /^# stdout end/ ).map do |line|
if line =~ /^# (.*\n)/ #..
$1
elsif line =~ /^#\/(.*)/ #..
Regexp.new($1)
else
line # should not occur
end
end
tests << [prefix, code, stdout]
end
puts "###"
puts "### found %d tests in file." % [tests.size]
puts "###"
act = ActualRegression.new
already_ok = DBM.open("already_ok")
if ! $opt_remember
already_ok.clear
end
errors = 0
iii = -1
for prefix, code, stdout in tests
iii += 1
next if $opt_only && iii != $opt_only
digest = Digest::MD5.hexdigest([prefix,code,stdout].flatten.join)
if already_ok.has_key?(digest)
#puts "### #{iii}: %s ... [[cahced]]" % [code[0].chomp]
next
end
code_str = code.join("\n")
if code_str =~ /REQUIRE: \s+ (.*)/x
expr = $1
if ! eval(expr)
puts "### #{iii}: SKIP: %s: %s ..." % [expr, code[0].chomp]
act.add(prefix, code, stdout)
next
end
end
puts "### #{iii}: %s ..." % [code[0].chomp]
lines = []
#lines << "require 'Test/Cmd'"
lines << ""
lines << "class TC_foo < Cmdtest::Testcase"
lines << ""
lines << " def test_foo"
lines << indent_lines(2, code)
lines << " end"
lines << ""
lines << "end"
lines << ""
lines.flatten!
File.open("CMDTEST_tmp_regression.rb", "w") do |f|
f.puts lines
end
res = my_system "ruby -w bin/cmdtest.rb --no-exit-code --quiet --ruby_s CMDTEST_tmp_regression.rb"
if res.status != 0
puts "ERROR: non-zero exit from:"
puts lines
exit 1
end
if matching_arrays(stdout, res.stdout)
already_ok[digest] = true
else
puts "ERROR: unexpected STDOUT:"
puts "ACTUAL:"
puts indented(res.stdout)
puts "EXPECTED:"
puts indented(stdout)
errors += 1
end
act.add(prefix, code, res.stdout)
end
act.write
puts
if errors == 0
puts "### all tests OK"
else
puts "--- error in #{errors} tests"
end
puts