224 lines
6.9 KiB
V
224 lines
6.9 KiB
V
import os
|
|
import rand
|
|
import term
|
|
import v.util.diff
|
|
import v.util.vtest
|
|
|
|
const vexe = @VEXE
|
|
|
|
const vroot = os.real_path(@VMODROOT)
|
|
|
|
const testdata_folder = os.join_path(vroot, 'vlib', 'v', 'gen', 'c', 'testdata')
|
|
|
|
const diff_cmd = diff.find_working_diff_command() or { '' }
|
|
|
|
const show_compilation_output = os.getenv('VTEST_SHOW_COMPILATION_OUTPUT').int() == 1
|
|
|
|
fn mm(s string) string {
|
|
return term.colorize(term.magenta, s)
|
|
}
|
|
|
|
fn test_out_files() ? {
|
|
println(term.colorize(term.green, '> testing whether .out files match:'))
|
|
os.chdir(vroot) or {}
|
|
output_path := os.join_path(os.temp_dir(), 'coutput', 'out')
|
|
os.mkdir_all(output_path) ?
|
|
defer {
|
|
os.rmdir_all(output_path) or {}
|
|
}
|
|
files := os.ls(testdata_folder) or { [] }
|
|
tests := files.filter(it.ends_with('.out'))
|
|
if tests.len == 0 {
|
|
eprintln('no `.out` tests found in $testdata_folder')
|
|
return
|
|
}
|
|
paths := vtest.filter_vtest_only(tests, basepath: testdata_folder)
|
|
mut total_errors := 0
|
|
for out_path in paths {
|
|
basename, path, relpath, out_relpath := target2paths(out_path, '.out')
|
|
pexe := os.join_path(output_path, '${basename}.exe')
|
|
//
|
|
file_options := get_file_options(path)
|
|
alloptions := '-o ${os.quoted_path(pexe)} $file_options.vflags'
|
|
print(mm('v $alloptions run $relpath') + ' == ${mm(out_relpath)} ')
|
|
//
|
|
compilation := os.execute('${os.quoted_path(vexe)} $alloptions ${os.quoted_path(path)}')
|
|
ensure_compilation_succeeded(compilation)
|
|
res := os.execute(os.quoted_path(pexe))
|
|
if res.exit_code < 0 {
|
|
println('nope')
|
|
panic(res.output)
|
|
}
|
|
mut found := res.output.trim_right('\r\n').replace('\r\n', '\n')
|
|
mut expected := os.read_file(out_path) ?
|
|
expected = expected.trim_right('\r\n').replace('\r\n', '\n')
|
|
if expected.contains('================ V panic ================') {
|
|
// panic include backtraces and absolute file paths, so can't do char by char comparison
|
|
n_found := normalize_panic_message(found, vroot)
|
|
n_expected := normalize_panic_message(expected, vroot)
|
|
if found.contains('================ V panic ================') {
|
|
if n_found.starts_with(n_expected) {
|
|
println(term.green('OK (panic)'))
|
|
continue
|
|
} else {
|
|
// Both have panics, but there was a difference...
|
|
// Pass the normalized strings for further reporting.
|
|
// There is no point in comparing the backtraces too.
|
|
found = n_found
|
|
expected = n_expected
|
|
}
|
|
}
|
|
}
|
|
if expected != found {
|
|
println(term.red('FAIL'))
|
|
println(term.header('expected:', '-'))
|
|
println(expected)
|
|
println(term.header('found:', '-'))
|
|
println(found)
|
|
if diff_cmd != '' {
|
|
println(term.header('difference:', '-'))
|
|
println(diff.color_compare_strings(diff_cmd, rand.ulid(), expected, found))
|
|
} else {
|
|
println(term.h_divider('-'))
|
|
}
|
|
total_errors++
|
|
} else {
|
|
println(term.green('OK'))
|
|
}
|
|
}
|
|
assert total_errors == 0
|
|
}
|
|
|
|
fn test_c_must_have_files() ? {
|
|
println(term.colorize(term.green, '> testing whether `.c.must_have` files match:'))
|
|
os.chdir(vroot) or {}
|
|
output_path := os.join_path(os.temp_dir(), 'coutput', 'c_must_have')
|
|
os.mkdir_all(output_path) ?
|
|
defer {
|
|
os.rmdir_all(output_path) or {}
|
|
}
|
|
files := os.ls(testdata_folder) or { [] }
|
|
tests := files.filter(it.ends_with('.c.must_have'))
|
|
if tests.len == 0 {
|
|
eprintln('no `.c.must_have` files found in $testdata_folder')
|
|
return
|
|
}
|
|
paths := vtest.filter_vtest_only(tests, basepath: testdata_folder)
|
|
mut total_errors := 0
|
|
mut failed_descriptions := []string{cap: paths.len}
|
|
for must_have_path in paths {
|
|
basename, path, relpath, must_have_relpath := target2paths(must_have_path, '.c.must_have')
|
|
file_options := get_file_options(path)
|
|
alloptions := '-o - $file_options.vflags'
|
|
description := mm('v $alloptions $relpath') +
|
|
' matches all line patterns in ${mm(must_have_relpath)} '
|
|
print(description)
|
|
cmd := '${os.quoted_path(vexe)} $alloptions ${os.quoted_path(path)}'
|
|
compilation := os.execute(cmd)
|
|
ensure_compilation_succeeded(compilation)
|
|
expected_lines := os.read_lines(must_have_path) or { [] }
|
|
generated_c_lines := compilation.output.split_into_lines()
|
|
mut nmatches := 0
|
|
mut failed_patterns := []string{}
|
|
for idx_expected_line, eline in expected_lines {
|
|
if does_line_match_one_of_generated_lines(eline, generated_c_lines) {
|
|
nmatches++
|
|
// eprintln('> testing: $must_have_path has line: $eline')
|
|
} else {
|
|
failed_patterns << eline
|
|
println(term.red('FAIL'))
|
|
eprintln('$must_have_path:${idx_expected_line + 1}: expected match error:')
|
|
eprintln('`$cmd` did NOT produce expected line:')
|
|
eprintln(term.colorize(term.red, eline))
|
|
if description !in failed_descriptions {
|
|
failed_descriptions << description
|
|
}
|
|
total_errors++
|
|
continue
|
|
}
|
|
}
|
|
if nmatches == expected_lines.len {
|
|
println(term.green('OK'))
|
|
} else {
|
|
if show_compilation_output {
|
|
eprintln('> ALL lines:')
|
|
eprintln(compilation.output)
|
|
}
|
|
eprintln('--------- failed patterns: -------------------------------------------')
|
|
for fpattern in failed_patterns {
|
|
eprintln(fpattern)
|
|
}
|
|
eprintln('----------------------------------------------------------------------')
|
|
}
|
|
}
|
|
if failed_descriptions.len > 0 {
|
|
eprintln('--------- failed commands: -------------------------------------------')
|
|
for fd in failed_descriptions {
|
|
eprintln(' > $fd')
|
|
}
|
|
eprintln('----------------------------------------------------------------------')
|
|
}
|
|
assert total_errors == 0
|
|
}
|
|
|
|
fn does_line_match_one_of_generated_lines(line string, generated_c_lines []string) bool {
|
|
for cline in generated_c_lines {
|
|
if line == cline {
|
|
return true
|
|
}
|
|
if cline.contains(line) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
fn normalize_panic_message(message string, vroot string) string {
|
|
mut msg := message.all_before('=========================================')
|
|
// change windows to nix path
|
|
s := vroot.replace(os.path_separator, '/')
|
|
msg = msg.replace(s + '/', '')
|
|
msg = msg.trim_space()
|
|
return msg
|
|
}
|
|
|
|
fn vroot_relative(opath string) string {
|
|
nvroot := vroot.replace(os.path_separator, '/') + '/'
|
|
npath := opath.replace(os.path_separator, '/')
|
|
return npath.replace(nvroot, '')
|
|
}
|
|
|
|
fn ensure_compilation_succeeded(compilation os.Result) {
|
|
if compilation.exit_code < 0 {
|
|
panic(compilation.output)
|
|
}
|
|
if compilation.exit_code != 0 {
|
|
panic('compilation failed: $compilation.output')
|
|
}
|
|
}
|
|
|
|
fn target2paths(target_path string, postfix string) (string, string, string, string) {
|
|
basename := os.file_name(target_path).replace(postfix, '')
|
|
target_dir := os.dir(target_path)
|
|
path := os.join_path(target_dir, '${basename}.vv')
|
|
relpath := vroot_relative(path)
|
|
target_relpath := vroot_relative(target_path)
|
|
return basename, path, relpath, target_relpath
|
|
}
|
|
|
|
struct FileOptions {
|
|
mut:
|
|
vflags string
|
|
}
|
|
|
|
pub fn get_file_options(file string) FileOptions {
|
|
mut res := FileOptions{}
|
|
lines := os.read_lines(file) or { [] }
|
|
for line in lines {
|
|
if line.starts_with('// vtest vflags:') {
|
|
res.vflags = line.all_after(':').trim_space()
|
|
}
|
|
}
|
|
return res
|
|
}
|