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:
parent
033b027361
commit
08016ab374
168
vlib/v/gen/c/coutput_test.v
Normal file
168
vlib/v/gen/c/coutput_test.v
Normal 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
|
||||
}
|
3
vlib/v/gen/c/testdata/const_references.c.must_have
vendored
Normal file
3
vlib/v/gen/c/testdata/const_references.c.must_have
vendored
Normal 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)
|
3
vlib/v/gen/c/testdata/const_references.out
vendored
Normal file
3
vlib/v/gen/c/testdata/const_references.out
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
1
|
||||
2
|
||||
3
|
11
vlib/v/gen/c/testdata/const_references.vv
vendored
Normal file
11
vlib/v/gen/c/testdata/const_references.vv
vendored
Normal 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))
|
||||
}
|
9
vlib/v/tests/const_reference_argument_test.v
Normal file
9
vlib/v/tests/const_reference_argument_test.v
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user