1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

v.gen.c: add vlib/v/gen/c/coutput_test.v, to ease testing of produced C output

This commit is contained in:
Delyan Angelov 2021-07-31 12:14:56 +03:00
parent 033b027361
commit 08016ab374
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
5 changed files with 194 additions and 0 deletions

168
vlib/v/gen/c/coutput_test.v Normal file
View File

@ -0,0 +1,168 @@
import os
import rand
import term
import v.util.diff
import v.util.vtest
const vexe = @VEXE
const vroot = @VMODROOT
const testdata_folder = os.join_path(vroot, 'vlib', 'v', 'gen', 'c', 'testdata')
const diff_cmd = diff.find_working_diff_command() or { '' }
fn test_out_files() ? {
println(term.colorize(term.green, '> testing whether .out files match:'))
os.chdir(vroot)
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')
print(term.colorize(term.magenta, 'v run $relpath') + ' == ' +
term.colorize(term.magenta, out_relpath) + ' ')
pexe := os.join_path(output_path, '${basename}.exe')
compilation := os.execute('VCOLORS=never $vexe -o $pexe $path')
ensure_compilation_succeeded(compilation)
res := os.execute(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)
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
for must_have_path in paths {
basename, path, relpath, must_have_relpath := target2paths(must_have_path, '.c.must_have')
print(term.colorize(term.magenta, 'v -o - $relpath') + ' matches all line paterns in ' +
term.colorize(term.magenta, must_have_relpath) + ' ')
compilation := os.execute('VCOLORS=never $vexe -o - $path')
ensure_compilation_succeeded(compilation)
expected_lines := os.read_lines(must_have_path) or { [] }
generated_c_lines := compilation.output.split_into_lines()
mut nmatches := 0
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 {
println(term.red('FAIL'))
eprintln('$must_have_path:${idx_expected_line + 1}: expected match error:')
eprintln('`$vexe -o - $path` does NOT produce expected line:')
eprintln(term.colorize(term.red, eline))
total_errors++
continue
}
}
if nmatches == expected_lines.len {
println(term.green('OK'))
}
}
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(path string) string {
return path.replace(os.path_separator, '/').replace('$vroot/', '')
}
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, '')
path := os.join_path(os.dir(target_path), '${basename}.vv')
relpath := vroot_relative(path)
target_relpath := vroot_relative(target_path)
return basename, path, relpath, target_relpath
}

View File

@ -0,0 +1,3 @@
VV_LOCAL_SYMBOL int main__a_const_accepting_fn(int* x, const int* const_x);
VV_LOCAL_SYMBOL int main__a_const_accepting_fn(int* x, const int* const_x) {
main__a_const_accepting_fn(&a, &b)

View File

@ -0,0 +1,3 @@
1
2
3

View File

@ -0,0 +1,11 @@
fn a_const_accepting_fn(x &int, const_x &int) int {
return *x + *const_x
}
fn main() {
a := 1
b := 2
println(a)
println(b)
println(a_const_accepting_fn(&a, &b))
}

View File

@ -0,0 +1,9 @@
fn a_const_accepting_fn(x &int, const_x &int) int {
return *x + *const_x
}
fn test_fn_with_const_ref_param_can_be_called() {
a := 1
b := 2
assert a_const_accepting_fn(&a, &b) == 3
}