tests: support `VTEST_ONLY_FN=*test_sincos* ./v test .` and `./v test -run-only test_sin .`
parent
5f0160bf11
commit
68ada041e6
|
@ -19,6 +19,10 @@ pub const hide_oks = os.getenv('VTEST_HIDE_OK') == '1'
|
||||||
|
|
||||||
pub const fail_fast = os.getenv('VTEST_FAIL_FAST') == '1'
|
pub const fail_fast = os.getenv('VTEST_FAIL_FAST') == '1'
|
||||||
|
|
||||||
|
pub const test_only = os.getenv('VTEST_ONLY').split_any(',')
|
||||||
|
|
||||||
|
pub const test_only_fn = os.getenv('VTEST_ONLY_FN').split_any(',')
|
||||||
|
|
||||||
pub const is_node_present = os.execute('node --version').exit_code == 0
|
pub const is_node_present = os.execute('node --version').exit_code == 0
|
||||||
|
|
||||||
pub const all_processes = os.execute('ps ax').output.split_any('\r\n')
|
pub const all_processes = os.execute('ps ax').output.split_any('\r\n')
|
||||||
|
|
|
@ -5,6 +5,13 @@ import os.cmdline
|
||||||
import testing
|
import testing
|
||||||
import v.pref
|
import v.pref
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
mut:
|
||||||
|
verbose bool
|
||||||
|
fail_fast bool
|
||||||
|
run_only []string
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
args := os.args.clone()
|
args := os.args.clone()
|
||||||
if os.args.last() == 'test' {
|
if os.args.last() == 'test' {
|
||||||
|
@ -14,7 +21,11 @@ fn main() {
|
||||||
args_to_executable := args[1..]
|
args_to_executable := args[1..]
|
||||||
mut args_before := cmdline.options_before(args_to_executable, ['test'])
|
mut args_before := cmdline.options_before(args_to_executable, ['test'])
|
||||||
mut args_after := cmdline.options_after(args_to_executable, ['test'])
|
mut args_after := cmdline.options_after(args_to_executable, ['test'])
|
||||||
fail_fast := extract_flag('-fail-fast', mut args_after, testing.fail_fast)
|
mut ctx := Context{}
|
||||||
|
ctx.fail_fast = extract_flag_bool('-fail-fast', mut args_after, testing.fail_fast)
|
||||||
|
ctx.verbose = extract_flag_bool('-v', mut args_after, false)
|
||||||
|
ctx.run_only = extract_flag_string_array('-run-only', mut args_after, testing.test_only_fn)
|
||||||
|
os.setenv('VTEST_ONLY_FN', ctx.run_only.join(','), true)
|
||||||
if args_after == ['v'] {
|
if args_after == ['v'] {
|
||||||
eprintln('`v test v` has been deprecated.')
|
eprintln('`v test v` has been deprecated.')
|
||||||
eprintln('Use `v test-all` instead.')
|
eprintln('Use `v test-all` instead.')
|
||||||
|
@ -24,21 +35,25 @@ fn main() {
|
||||||
backend := if backend_pos == -1 { '.c' } else { args_before[backend_pos + 1] } // this giant mess because closures are not implemented
|
backend := if backend_pos == -1 { '.c' } else { args_before[backend_pos + 1] } // this giant mess because closures are not implemented
|
||||||
|
|
||||||
mut ts := testing.new_test_session(args_before.join(' '), true)
|
mut ts := testing.new_test_session(args_before.join(' '), true)
|
||||||
ts.fail_fast = fail_fast
|
ts.fail_fast = ctx.fail_fast
|
||||||
for targ in args_after {
|
for targ in args_after {
|
||||||
if os.is_dir(targ) {
|
if os.is_dir(targ) {
|
||||||
// Fetch all tests from the directory
|
// Fetch all tests from the directory
|
||||||
files, skip_files := should_test_dir(targ.trim_right(os.path_separator), backend)
|
files, skip_files := ctx.should_test_dir(targ.trim_right(os.path_separator),
|
||||||
|
backend)
|
||||||
ts.files << files
|
ts.files << files
|
||||||
ts.skip_files << skip_files
|
ts.skip_files << skip_files
|
||||||
continue
|
continue
|
||||||
} else if os.exists(targ) {
|
} else if os.exists(targ) {
|
||||||
match should_test(targ, backend) {
|
match ctx.should_test(targ, backend) {
|
||||||
.test {
|
.test {
|
||||||
ts.files << targ
|
ts.files << targ
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
.skip {
|
.skip {
|
||||||
|
if ctx.run_only.len > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
ts.files << targ
|
ts.files << targ
|
||||||
ts.skip_files << targ
|
ts.skip_files << targ
|
||||||
continue
|
continue
|
||||||
|
@ -71,7 +86,7 @@ fn show_usage() {
|
||||||
println('')
|
println('')
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_test_dir(path string, backend string) ([]string, []string) { // return is (files, skip_files)
|
pub fn (mut ctx Context) should_test_dir(path string, backend string) ([]string, []string) { // return is (files, skip_files)
|
||||||
mut files := os.ls(path) or { return []string{}, []string{} }
|
mut files := os.ls(path) or { return []string{}, []string{} }
|
||||||
mut local_path_separator := os.path_separator
|
mut local_path_separator := os.path_separator
|
||||||
if path.ends_with(os.path_separator) {
|
if path.ends_with(os.path_separator) {
|
||||||
|
@ -85,15 +100,18 @@ pub fn should_test_dir(path string, backend string) ([]string, []string) { // re
|
||||||
if file == 'testdata' {
|
if file == 'testdata' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ret_files, ret_skip_files := should_test_dir(p, backend)
|
ret_files, ret_skip_files := ctx.should_test_dir(p, backend)
|
||||||
res_files << ret_files
|
res_files << ret_files
|
||||||
skip_files << ret_skip_files
|
skip_files << ret_skip_files
|
||||||
} else if os.exists(p) {
|
} else if os.exists(p) {
|
||||||
match should_test(p, backend) {
|
match ctx.should_test(p, backend) {
|
||||||
.test {
|
.test {
|
||||||
res_files << p
|
res_files << p
|
||||||
}
|
}
|
||||||
.skip {
|
.skip {
|
||||||
|
if ctx.run_only.len > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
res_files << p
|
res_files << p
|
||||||
skip_files << p
|
skip_files << p
|
||||||
}
|
}
|
||||||
|
@ -110,7 +128,7 @@ enum ShouldTestStatus {
|
||||||
ignore // just ignore the file, so it will not be printed at all in the list of tests
|
ignore // just ignore the file, so it will not be printed at all in the list of tests
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_test(path string, backend string) ShouldTestStatus {
|
fn (mut ctx Context) should_test(path string, backend string) ShouldTestStatus {
|
||||||
if path.ends_with('mysql_orm_test.v') {
|
if path.ends_with('mysql_orm_test.v') {
|
||||||
testing.find_started_process('mysqld') or { return .skip }
|
testing.find_started_process('mysqld') or { return .skip }
|
||||||
}
|
}
|
||||||
|
@ -126,11 +144,11 @@ fn should_test(path string, backend string) ShouldTestStatus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if path.ends_with('_test.v') {
|
if path.ends_with('_test.v') {
|
||||||
return .test
|
return ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||||
}
|
}
|
||||||
if path.ends_with('_test.js.v') {
|
if path.ends_with('_test.js.v') {
|
||||||
if testing.is_node_present {
|
if testing.is_node_present {
|
||||||
return .test
|
return ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||||
}
|
}
|
||||||
return .skip
|
return .skip
|
||||||
}
|
}
|
||||||
|
@ -141,13 +159,21 @@ fn should_test(path string, backend string) ShouldTestStatus {
|
||||||
backend_arg := path.all_before_last('.v').all_after_last('.')
|
backend_arg := path.all_before_last('.v').all_after_last('.')
|
||||||
arch := pref.arch_from_string(backend_arg) or { pref.Arch._auto }
|
arch := pref.arch_from_string(backend_arg) or { pref.Arch._auto }
|
||||||
if arch == pref.get_host_arch() {
|
if arch == pref.get_host_arch() {
|
||||||
return .test
|
return ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||||
} else if arch == ._auto {
|
} else if arch == ._auto {
|
||||||
if backend_arg == 'c' { // .c.v
|
if backend_arg == 'c' { // .c.v
|
||||||
return if backend == 'c' { ShouldTestStatus.test } else { ShouldTestStatus.skip }
|
return if backend == 'c' {
|
||||||
|
ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||||
|
} else {
|
||||||
|
ShouldTestStatus.skip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if backend_arg == 'js' {
|
if backend_arg == 'js' {
|
||||||
return if backend == 'js' { ShouldTestStatus.test } else { ShouldTestStatus.skip }
|
return if backend == 'js' {
|
||||||
|
ctx.should_test_when_it_contains_matching_fns(path, backend)
|
||||||
|
} else {
|
||||||
|
ShouldTestStatus.skip
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return .skip
|
return .skip
|
||||||
|
@ -156,7 +182,33 @@ fn should_test(path string, backend string) ShouldTestStatus {
|
||||||
return .ignore
|
return .ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_flag(flag_name string, mut after []string, flag_default bool) bool {
|
fn (mut ctx Context) should_test_when_it_contains_matching_fns(path string, backend string) ShouldTestStatus {
|
||||||
|
if ctx.run_only.len == 0 {
|
||||||
|
// no filters set, so just compile and test
|
||||||
|
return .test
|
||||||
|
}
|
||||||
|
lines := os.read_lines(path) or { return .ignore }
|
||||||
|
for line in lines {
|
||||||
|
if line.match_glob('fn test_*') || line.match_glob('pub fn test_*') {
|
||||||
|
tname := line.replace_each(['pub fn ', '', 'fn ', '']).all_before('(')
|
||||||
|
for pattern in ctx.run_only {
|
||||||
|
mut pat := pattern.clone()
|
||||||
|
if pat.contains('.') {
|
||||||
|
pat = pat.all_after_last('.')
|
||||||
|
}
|
||||||
|
if tname.match_glob(pat) {
|
||||||
|
if ctx.verbose {
|
||||||
|
println('> compiling path: $path, since test fn `$tname` matches glob pattern `$pat`')
|
||||||
|
}
|
||||||
|
return .test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_flag_bool(flag_name string, mut after []string, flag_default bool) bool {
|
||||||
mut res := flag_default
|
mut res := flag_default
|
||||||
orig_after := after.clone() // workaround for after.filter() codegen bug, when `mut after []string`
|
orig_after := after.clone() // workaround for after.filter() codegen bug, when `mut after []string`
|
||||||
matches_after := orig_after.filter(it != flag_name)
|
matches_after := orig_after.filter(it != flag_name)
|
||||||
|
@ -166,3 +218,16 @@ fn extract_flag(flag_name string, mut after []string, flag_default bool) bool {
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_flag_string_array(flag_name string, mut after []string, flag_default []string) []string {
|
||||||
|
mut res := flag_default.clone()
|
||||||
|
mut found := after.index(flag_name)
|
||||||
|
if found > -1 {
|
||||||
|
if found + 1 < after.len {
|
||||||
|
res = after[found + 1].split_any(',')
|
||||||
|
after.delete(found)
|
||||||
|
}
|
||||||
|
after.delete(found)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
|
@ -190,7 +190,8 @@ pub fn (mut g Gen) gen_c_main_for_tests() {
|
||||||
g.writeln('\tmain__vtest_init();')
|
g.writeln('\tmain__vtest_init();')
|
||||||
g.writeln('\t_vinit(___argc, (voidptr)___argv);')
|
g.writeln('\t_vinit(___argc, (voidptr)___argv);')
|
||||||
//
|
//
|
||||||
all_tfuncs := g.get_all_test_function_names()
|
mut all_tfuncs := g.get_all_test_function_names()
|
||||||
|
all_tfuncs = g.filter_only_matching_fn_names(all_tfuncs)
|
||||||
g.writeln('\tstring v_test_file = ${ctoslit(g.pref.path)};')
|
g.writeln('\tstring v_test_file = ${ctoslit(g.pref.path)};')
|
||||||
if g.pref.is_stats {
|
if g.pref.is_stats {
|
||||||
g.writeln('\tmain__BenchedTests bt = main__start_testing($all_tfuncs.len, v_test_file);')
|
g.writeln('\tmain__BenchedTests bt = main__start_testing($all_tfuncs.len, v_test_file);')
|
||||||
|
@ -248,3 +249,28 @@ pub fn (mut g Gen) gen_c_main_for_tests() {
|
||||||
println(g.out.after(main_fn_start_pos))
|
println(g.out.after(main_fn_start_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut g Gen) filter_only_matching_fn_names(fnames []string) []string {
|
||||||
|
if g.pref.run_only.len == 0 {
|
||||||
|
return fnames
|
||||||
|
}
|
||||||
|
mut res := []string{}
|
||||||
|
for tname in fnames {
|
||||||
|
if tname.contains('testsuite_') {
|
||||||
|
res << tname
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mut is_matching := false
|
||||||
|
for fn_glob_pattern in g.pref.run_only {
|
||||||
|
if tname.match_glob(fn_glob_pattern) {
|
||||||
|
is_matching = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !is_matching {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
res << tname
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
|
@ -162,6 +162,8 @@ pub mut:
|
||||||
out_name string
|
out_name string
|
||||||
path string // Path to file/folder to compile
|
path string // Path to file/folder to compile
|
||||||
// -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }`
|
// -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }`
|
||||||
|
run_only []string // VTEST_ONLY_FN and -run-only accept comma separated glob patterns.
|
||||||
|
// Only test_ functions that match these patterns will be run. -run-only is valid only for _test.v files.
|
||||||
compile_defines []string // just ['vfmt']
|
compile_defines []string // just ['vfmt']
|
||||||
compile_defines_all []string // contains both: ['vfmt','another']
|
compile_defines_all []string // contains both: ['vfmt','another']
|
||||||
run_args []string // `v run x.v 1 2 3` => `1 2 3`
|
run_args []string // `v run x.v 1 2 3` => `1 2 3`
|
||||||
|
@ -207,6 +209,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||||
$if x64 {
|
$if x64 {
|
||||||
res.m64 = true // follow V model by default
|
res.m64 = true // follow V model by default
|
||||||
}
|
}
|
||||||
|
res.run_only = os.getenv('VTEST_ONLY_FN').split_any(',')
|
||||||
mut command := ''
|
mut command := ''
|
||||||
mut command_pos := 0
|
mut command_pos := 0
|
||||||
// for i, arg in args {
|
// for i, arg in args {
|
||||||
|
@ -466,6 +469,10 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin
|
||||||
'-show-depgraph' {
|
'-show-depgraph' {
|
||||||
res.show_depgraph = true
|
res.show_depgraph = true
|
||||||
}
|
}
|
||||||
|
'-run-only' {
|
||||||
|
res.run_only = cmdline.option(current_args, arg, os.getenv('VTEST_ONLY_FN')).split_any(',')
|
||||||
|
i++
|
||||||
|
}
|
||||||
'-test-runner' {
|
'-test-runner' {
|
||||||
res.test_runner = cmdline.option(current_args, arg, res.test_runner)
|
res.test_runner = cmdline.option(current_args, arg, res.test_runner)
|
||||||
i++
|
i++
|
||||||
|
|
Loading…
Reference in New Issue