blob: 1dc451a4bd3eb5705a2ba6f03b332e7af8bb6007 [file] [log] [blame]
#!/usr/bin/env ruby
require 'fileutils'
if ARGV[0] == '-s'
test_serialization = true
end
def get_output_filenames
files = Dir.glob('*')
files.delete('Makefile')
files.reject!{|f|f =~ /\.json$/}
files
end
def cleanup
(get_output_filenames + Dir.glob('.*')).each do |fname|
next if fname == '.' || fname == '..'
FileUtils.rm_rf fname
end
end
def move_circular_dep(l)
# We don't care when circular dependency detection happens.
circ = ''
while l.sub!(/Circular .* dropped\.\n/, '') do
circ += $&
end
circ + l
end
expected_failures = []
unexpected_passes = []
failures = []
passes = []
if !ARGV.empty?
test_files = ARGV.map do |test|
"testcase/#{File.basename(test)}"
end
else
test_files = Dir.glob('testcase/*.mk').sort
test_files += Dir.glob('testcase/*.sh').sort
end
def run_in_testdir(test_filename)
c = File.read(test_filename)
name = File.basename(test_filename)
dir = "out/#{name}"
FileUtils.mkdir_p(dir)
Dir.glob("#{dir}/*").each do |fname|
FileUtils.rm_rf(fname)
end
Dir.chdir(dir) do
yield name
end
end
def normalize_make_log(expected)
expected.gsub!(/^make(?:\[\d+\])?: (Entering|Leaving) directory.*\n/, '')
expected.gsub!(/^make(?:\[\d+\])?: /, '')
expected = move_circular_dep(expected)
# Normalizations for old/new GNU make.
expected.gsub!(/[`'"]/, '"')
expected.gsub!(/ (?:commands|recipe) for target /,
' commands for target ')
expected.gsub!(/ (?:commands|recipe) commences /,
' commands commence ')
expected.gsub!(' (did you mean TAB instead of 8 spaces?)', '')
expected.gsub!('Extraneous text after', 'extraneous text after')
# Not sure if this is useful.
expected.gsub!(/\s+Stop\.$/, '')
# GNU make 4.0 has this output.
expected.gsub!(/Makefile:\d+: commands for target ".*?" failed\n/, '')
# We treat some warnings as errors.
expected.gsub!(/Nothing to be done for "test"\.\n/, '')
expected
end
def normalize_kati_log(output)
output = move_circular_dep(output)
# kati specific log messages.
output.gsub!(/^\*kati\*.*\n/, '')
output.gsub!(/[`'"]/, '"')
output.gsub!(/(: )open (\S+): n(o such file or directory)\nNOTE:.*/,
"\\1\\2: N\\3\n*** No rule to make target \"\\2\".")
output
end
run_make_test = proc do |mk|
c = File.read(mk)
expected_failure = c =~ /\A# TODO/
run_in_testdir(mk) do |name|
File.open("Makefile", 'w') do |ofile|
ofile.print(c)
end
expected = ''
output = ''
testcases = c.scan(/^test\d*/).sort.uniq
if testcases.empty?
testcases = ['']
end
cleanup
testcases.each do |tc|
res = `make #{tc} 2>&1`
res = normalize_make_log(res)
expected += "=== #{tc} ===\n" + res
expected_files = get_output_filenames
expected += "\n=== FILES ===\n#{expected_files * "\n"}\n"
end
cleanup
testcases.each do |tc|
json = "#{tc.empty? ? 'test' : tc}"
cmd = "../../kati -save_json=#{json}.json -kati_log #{tc} 2>&1"
res = IO.popen(cmd, 'r:binary', &:read)
res = normalize_kati_log(res)
output += "=== #{tc} ===\n" + res
output_files = get_output_filenames
output += "\n=== FILES ===\n#{output_files * "\n"}\n"
end
File.open('out.make', 'w'){|ofile|ofile.print(expected)}
File.open('out.kati', 'w'){|ofile|ofile.print(output)}
if expected =~ /FAIL/
puts %Q(#{name} has a string "FAIL" in its expectation)
exit 1
end
if expected != output
if expected_failure
puts "#{name}: FAIL (expected)"
expected_failures << name
else
puts "#{name}: FAIL"
puts `diff -u out.make out.kati`
failures << name
end
else
if expected_failure
puts "#{name}: PASS (unexpected)"
unexpected_passes << name
else
puts "#{name}: PASS"
passes << name
end
end
if name !~ /^err_/ && test_serialization && !expected_failure
testcases.each do |tc|
json = "#{tc.empty? ? 'test' : tc}"
cmd = "../../kati -save_json=#{json}_2.json -load_json=#{json}.json -n -kati_log #{tc} 2>&1"
res = IO.popen(cmd, 'r:binary', &:read)
if !File.exist?("#{json}.json") || !File.exist?("#{json}_2.json")
puts "#{name}##{json}: Serialize failure (not exist)"
puts res
else
json1 = File.read("#{json}.json")
json2 = File.read("#{json}_2.json")
if json1 != json2
puts "#{name}##{json}: Serialize failure"
puts res
end
end
end
end
end
end
run_shell_test = proc do |sh|
run_in_testdir(sh) do |name|
cleanup
cmd = "sh ../../#{sh} make"
expected = IO.popen(cmd, 'r:binary', &:read)
cleanup
cmd = "sh ../../#{sh} ../../kati --use_cache --kati_log"
output = IO.popen(cmd, 'r:binary', &:read)
expected = normalize_make_log(expected)
output = normalize_kati_log(output)
File.open('out.make', 'w'){|ofile|ofile.print(expected)}
File.open('out.kati', 'w'){|ofile|ofile.print(output)}
if expected != output
puts "#{name}: FAIL"
puts `diff -u out.make out.kati`
failures << name
else
puts "#{name}: PASS"
passes << name
end
end
end
test_files.each do |test|
if /\.mk$/ =~ test
run_make_test.call(test)
elsif /\.sh$/ =~ test
run_shell_test.call(test)
else
raise "Unknown test type: #{test}"
end
end
puts
if !expected_failures.empty?
puts "=== Expected failures ==="
expected_failures.each do |n|
puts n
end
end
if !unexpected_passes.empty?
puts "=== Unexpected passes ==="
unexpected_passes.each do |n|
puts n
end
end
if !failures.empty?
puts "=== Failures ==="
failures.each do |n|
puts n
end
end
puts
if !unexpected_passes.empty? || !failures.empty?
puts 'FAIL!'
else
puts 'PASS!'
end