v test: add ability to test a folder or a set of _test.v files
* v test: support for running 'v test folder/' . * Support passing multiple folders and also single _test.v files to 'v test' . * Update vhelp too, with descriptions of v test folder/ and v -stats . * Fix running `v test v` from outside the root of the v tree.pull/2267/head
parent
f570cbfca8
commit
dbd72ee828
|
@ -224,7 +224,26 @@ fn (s mut Scanner) get_scanner_pos_of_token(t &Token) ScannerPos {
|
||||||
// of the token. Continue scanning for some more lines of context too.
|
// of the token. Continue scanning for some more lines of context too.
|
||||||
s.goto_scanner_position(ScannerPos{})
|
s.goto_scanner_position(ScannerPos{})
|
||||||
s.file_lines = []string
|
s.file_lines = []string
|
||||||
|
|
||||||
mut prevlinepos := 0
|
mut prevlinepos := 0
|
||||||
|
// NB: TCC BUG workaround: removing the `mut ate:=0 ate++` line
|
||||||
|
// below causes a bug in v, when v is compiled with tcc, and v
|
||||||
|
// wants to report the error: 'the following imports were never used:'
|
||||||
|
//
|
||||||
|
// This can be reproduced, if you follow the steps:
|
||||||
|
// a) ./v -cc tcc -o v compiler ;
|
||||||
|
// b) ./v vlib/builtin/hashmap_test.v'
|
||||||
|
//
|
||||||
|
// In this case, prevlinepos gets a random value on each run.
|
||||||
|
// Any kind of operation may be used seemingly, as long as
|
||||||
|
// there is a new stack allocation that will 'protect' prevlinepos.
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
mut ate:=0 ate++ // This var will be smashed by TCC, instead of
|
||||||
|
/////////////////// prevlinepos. The cause is the call to
|
||||||
|
/////////////////// s.get_scanner_pos()
|
||||||
|
/////////////////// which just returns a struct, and that works
|
||||||
|
/////////////////// in gcc and clang, but causes the TCC problem.
|
||||||
|
|
||||||
for {
|
for {
|
||||||
prevlinepos = s.pos
|
prevlinepos = s.pos
|
||||||
if s.pos >= s.text.len { break }
|
if s.pos >= s.text.len { break }
|
||||||
|
|
129
compiler/main.v
129
compiler/main.v
|
@ -8,7 +8,6 @@ import (
|
||||||
os
|
os
|
||||||
strings
|
strings
|
||||||
benchmark
|
benchmark
|
||||||
term
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -154,12 +153,12 @@ fn main() {
|
||||||
vfmt(args)
|
vfmt(args)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Construct the V object from command line arguments
|
if 'test' in args {
|
||||||
mut v := new_v(args)
|
test_v()
|
||||||
if args.join(' ').contains(' test v') {
|
|
||||||
v.test_v()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Construct the V object from command line arguments
|
||||||
|
mut v := new_v(args)
|
||||||
if v.pref.is_verbose {
|
if v.pref.is_verbose {
|
||||||
println(args)
|
println(args)
|
||||||
}
|
}
|
||||||
|
@ -741,10 +740,10 @@ fn (v &V) resolve_deps() &DepGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_arg(joined_args, arg, def string) string {
|
fn get_arg(joined_args, arg, def string) string {
|
||||||
return get_all_after(joined_args, '-$arg', def)
|
return get_param_after(joined_args, '-$arg', def)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_all_after(joined_args, arg, def string) string {
|
fn get_param_after(joined_args, arg, def string) string {
|
||||||
key := '$arg '
|
key := '$arg '
|
||||||
mut pos := joined_args.index(key)
|
mut pos := joined_args.index(key)
|
||||||
if pos == -1 {
|
if pos == -1 {
|
||||||
|
@ -756,7 +755,6 @@ fn get_all_after(joined_args, arg, def string) string {
|
||||||
space = joined_args.len
|
space = joined_args.len
|
||||||
}
|
}
|
||||||
res := joined_args.substr(pos, space)
|
res := joined_args.substr(pos, space)
|
||||||
// println('get_arg($arg) = "$res"')
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,7 +775,7 @@ fn new_v(args[]string) &V {
|
||||||
|
|
||||||
mut dir := args.last()
|
mut dir := args.last()
|
||||||
if 'run' in args {
|
if 'run' in args {
|
||||||
dir = get_all_after(joined_args, 'run', '')
|
dir = get_param_after(joined_args, 'run', '')
|
||||||
}
|
}
|
||||||
if dir.ends_with(os.PathSeparator) {
|
if dir.ends_with(os.PathSeparator) {
|
||||||
dir = dir.all_before_last(os.PathSeparator)
|
dir = dir.all_before_last(os.PathSeparator)
|
||||||
|
@ -1038,119 +1036,6 @@ fn install_v(args[]string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (v &V) test_vget() {
|
|
||||||
/*
|
|
||||||
vexe := os.executable()
|
|
||||||
ret := os.system('$vexe install nedpals.args')
|
|
||||||
if ret != 0 {
|
|
||||||
println('failed to run v install')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
if !os.file_exists(v_modules_path + '/nedpals/args') {
|
|
||||||
println('v failed to install a test module')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
println('vget is OK')
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (v &V) test_v() {
|
|
||||||
args := env_vflags_and_os_args()
|
|
||||||
vexe := os.executable()
|
|
||||||
parent_dir := os.dir(vexe)
|
|
||||||
if !os.dir_exists(parent_dir + '/vlib') {
|
|
||||||
println('vlib/ is missing, it must be next to the V executable')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
if !os.dir_exists(parent_dir + '/compiler') {
|
|
||||||
println('compiler/ is missing, it must be next to the V executable')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
// Make sure v.c can be compiled without warnings
|
|
||||||
$if mac {
|
|
||||||
os.system('$vexe -o v.c compiler')
|
|
||||||
if os.system('cc -Werror v.c') != 0 {
|
|
||||||
println('cc failed to build v.c without warnings')
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
println('v.c can be compiled without warnings. This is good :)')
|
|
||||||
}
|
|
||||||
// Emily: pass args from the invocation to the test
|
|
||||||
// e.g. `v -g -os msvc test v` -> `$vexe -g -os msvc $file`
|
|
||||||
mut joined_args := args.right(1).join(' ')
|
|
||||||
joined_args = joined_args.left(joined_args.last_index('test'))
|
|
||||||
// println('$joined_args')
|
|
||||||
mut failed := false
|
|
||||||
test_files := os.walk_ext(parent_dir, '_test.v')
|
|
||||||
|
|
||||||
ok := term.ok_message('OK')
|
|
||||||
fail := term.fail_message('FAIL')
|
|
||||||
println('Testing...')
|
|
||||||
mut tmark := benchmark.new_benchmark()
|
|
||||||
for dot_relative_file in test_files {
|
|
||||||
relative_file := dot_relative_file.replace('./', '')
|
|
||||||
file := os.realpath( relative_file )
|
|
||||||
tmpc_filepath := file.replace('_test.v', '_test.tmp.c')
|
|
||||||
|
|
||||||
mut cmd := '"$vexe" $joined_args -debug "$file"'
|
|
||||||
if os.user_os() == 'windows' { cmd = '"$cmd"' }
|
|
||||||
|
|
||||||
tmark.step()
|
|
||||||
r := os.exec(cmd) or {
|
|
||||||
tmark.fail()
|
|
||||||
failed = true
|
|
||||||
println(tmark.step_message('$relative_file $fail'))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if r.exit_code != 0 {
|
|
||||||
failed = true
|
|
||||||
tmark.fail()
|
|
||||||
println(tmark.step_message('$relative_file $fail\n`$file`\n (\n$r.output\n)'))
|
|
||||||
} else {
|
|
||||||
tmark.ok()
|
|
||||||
println(tmark.step_message('$relative_file $ok'))
|
|
||||||
}
|
|
||||||
os.rm( tmpc_filepath )
|
|
||||||
}
|
|
||||||
tmark.stop()
|
|
||||||
println( tmark.total_message('running V tests') )
|
|
||||||
|
|
||||||
println('\nBuilding examples...')
|
|
||||||
examples := os.walk_ext(parent_dir + '/examples', '.v')
|
|
||||||
mut bmark := benchmark.new_benchmark()
|
|
||||||
for relative_file in examples {
|
|
||||||
if relative_file.contains('vweb') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
file := os.realpath( relative_file )
|
|
||||||
tmpc_filepath := file.replace('.v', '.tmp.c')
|
|
||||||
mut cmd := '"$vexe" $joined_args -debug "$file"'
|
|
||||||
if os.user_os() == 'windows' { cmd = '"$cmd"' }
|
|
||||||
bmark.step()
|
|
||||||
r := os.exec(cmd) or {
|
|
||||||
failed = true
|
|
||||||
bmark.fail()
|
|
||||||
println(bmark.step_message('$relative_file $fail'))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if r.exit_code != 0 {
|
|
||||||
failed = true
|
|
||||||
bmark.fail()
|
|
||||||
println(bmark.step_message('$relative_file $fail \n`$file`\n (\n$r.output\n)'))
|
|
||||||
} else {
|
|
||||||
bmark.ok()
|
|
||||||
println(bmark.step_message('$relative_file $ok'))
|
|
||||||
}
|
|
||||||
os.rm(tmpc_filepath)
|
|
||||||
}
|
|
||||||
bmark.stop()
|
|
||||||
println( bmark.total_message('building examples') )
|
|
||||||
v.test_vget()
|
|
||||||
if failed {
|
|
||||||
exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_symlink() {
|
fn create_symlink() {
|
||||||
vexe := os.executable()
|
vexe := os.executable()
|
||||||
link_path := '/usr/local/bin/v'
|
link_path := '/usr/local/bin/v'
|
||||||
|
|
|
@ -46,6 +46,7 @@ Options/commands:
|
||||||
Example: -cflags `sdl2-config --cflags`
|
Example: -cflags `sdl2-config --cflags`
|
||||||
-debug Keep the generated C file for debugging in program.tmp.c even after compilation.
|
-debug Keep the generated C file for debugging in program.tmp.c even after compilation.
|
||||||
-shared Build a shared library.
|
-shared Build a shared library.
|
||||||
|
-stats Show additional stats when compiling/running tests. Try `v -stats test .`
|
||||||
-g Show v line numbers in backtraces. Implies -debug.
|
-g Show v line numbers in backtraces. Implies -debug.
|
||||||
-obf Obfuscate the resulting binary.
|
-obf Obfuscate the resulting binary.
|
||||||
-show_c_cmd Print the full C compilation command and how much time it took.
|
-show_c_cmd Print the full C compilation command and how much time it took.
|
||||||
|
@ -58,6 +59,7 @@ Options/commands:
|
||||||
symlink Useful on unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available.
|
symlink Useful on unix systems. Symlinks the current V executable to /usr/local/bin/v, so that V is globally available.
|
||||||
install <module> Install a user module from https://vpm.vlang.io/.
|
install <module> Install a user module from https://vpm.vlang.io/.
|
||||||
test v Run all V test files, and compile all V examples.
|
test v Run all V test files, and compile all V examples.
|
||||||
|
test folder/ Run all V test files located in the folder and its subfolders. You can also pass individual _test.v files too.
|
||||||
fmt Run vfmt to format the source code. [wip]
|
fmt Run vfmt to format the source code. [wip]
|
||||||
doc Run vdoc over the source code and produce documentation. [wip]
|
doc Run vdoc over the source code and produce documentation. [wip]
|
||||||
translate Translates C to V. [wip, will be available in V 0.3]
|
translate Translates C to V. [wip, will be available in V 0.3]
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
module main
|
||||||
|
|
||||||
|
import (
|
||||||
|
os
|
||||||
|
term
|
||||||
|
benchmark
|
||||||
|
)
|
||||||
|
|
||||||
|
struct TestSession {
|
||||||
|
mut:
|
||||||
|
files []string
|
||||||
|
vexe string
|
||||||
|
vargs string
|
||||||
|
failed bool
|
||||||
|
benchmark benchmark.Benchmark
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_test_sesion(vargs string) TestSession {
|
||||||
|
return TestSession{
|
||||||
|
vexe: os.executable()
|
||||||
|
vargs: vargs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_v() {
|
||||||
|
args := os.args
|
||||||
|
if args.last() == 'test' {
|
||||||
|
println('Usage:')
|
||||||
|
println(' A)')
|
||||||
|
println(' v test v : run all v tests and build all the examples')
|
||||||
|
println(' B)')
|
||||||
|
println(' v test folder/ : run all v tests in the given folder.')
|
||||||
|
println(' v -stats test folder/ : the same, but print more stats.')
|
||||||
|
println(' C)')
|
||||||
|
println(' v test file_test.v : run test functions in a given test file.')
|
||||||
|
println(' v -stats test file_test.v : as above, but with more stats.')
|
||||||
|
println(' NB: you can also give many and mixed folder/ file_test.v arguments after test.')
|
||||||
|
println('')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
args_string := args.right(1).join(' ')
|
||||||
|
args_before := args_string.all_before('test ')
|
||||||
|
args_after := args_string.all_after('test ')
|
||||||
|
|
||||||
|
if args_after == 'v' {
|
||||||
|
v_test_v(args_before)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mut ts := new_test_sesion(args_before)
|
||||||
|
for targ in args_after.split(' ') {
|
||||||
|
if os.file_exists(targ) && targ.ends_with('_test.v') {
|
||||||
|
ts.files << targ
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if os.dir_exists(targ) {
|
||||||
|
|
||||||
|
ts.files << os.walk_ext( targ.trim_right(os.PathSeparator), '_test.v')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
println('Unrecognized test file $targ .')
|
||||||
|
}
|
||||||
|
|
||||||
|
println('Testing...')
|
||||||
|
ts.test()
|
||||||
|
println('----------------------------------------------------------------------------')
|
||||||
|
println( ts.benchmark.total_message('running V _test.v files') )
|
||||||
|
if ts.failed {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (ts mut TestSession) test() {
|
||||||
|
ok := term.ok_message('OK')
|
||||||
|
fail := term.fail_message('FAIL')
|
||||||
|
cmd_needs_quoting := (os.user_os() == 'windows')
|
||||||
|
show_stats := '-stats' in ts.vargs.split(' ')
|
||||||
|
ts.benchmark = benchmark.new_benchmark()
|
||||||
|
for dot_relative_file in ts.files {
|
||||||
|
relative_file := dot_relative_file.replace('./', '')
|
||||||
|
file := os.realpath( relative_file )
|
||||||
|
tmpc_filepath := file.replace('.v', '.tmp.c')
|
||||||
|
|
||||||
|
mut cmd := '"$ts.vexe" $ts.vargs "$file"'
|
||||||
|
if cmd_needs_quoting { cmd = '"$cmd"' }
|
||||||
|
|
||||||
|
ts.benchmark.step()
|
||||||
|
if show_stats {
|
||||||
|
println('-------------------------------------------------')
|
||||||
|
status := os.system(cmd)
|
||||||
|
if status == 0 {
|
||||||
|
ts.benchmark.ok()
|
||||||
|
}else{
|
||||||
|
ts.benchmark.fail()
|
||||||
|
ts.failed = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
r := os.exec(cmd) or {
|
||||||
|
ts.benchmark.fail()
|
||||||
|
ts.failed = true
|
||||||
|
println(ts.benchmark.step_message('$relative_file $fail'))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if r.exit_code != 0 {
|
||||||
|
ts.benchmark.fail()
|
||||||
|
ts.failed = true
|
||||||
|
println(ts.benchmark.step_message('$relative_file $fail\n`$file`\n (\n$r.output\n)'))
|
||||||
|
} else {
|
||||||
|
ts.benchmark.ok()
|
||||||
|
println(ts.benchmark.step_message('$relative_file $ok'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os.rm( tmpc_filepath )
|
||||||
|
}
|
||||||
|
ts.benchmark.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stable_example(example string, index int, arr []string) bool {
|
||||||
|
return !example.contains('vweb')
|
||||||
|
}
|
||||||
|
|
||||||
|
fn v_test_v(args_before_test string){
|
||||||
|
vexe := os.executable()
|
||||||
|
parent_dir := os.dir(vexe)
|
||||||
|
// Changing the current directory is needed for some of the compiler tests,
|
||||||
|
// compiler/tests/local_test.v and compiler/tests/repl/repl_test.v
|
||||||
|
os.chdir( parent_dir )
|
||||||
|
if !os.dir_exists(parent_dir + '/vlib') {
|
||||||
|
println('vlib/ is missing, it must be next to the V executable')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
if !os.dir_exists(parent_dir + '/compiler') {
|
||||||
|
println('compiler/ is missing, it must be next to the V executable')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
// Make sure v.c can be compiled without warnings
|
||||||
|
$if mac {
|
||||||
|
os.system('$vexe -o v.c compiler')
|
||||||
|
if os.system('cc -Werror v.c') != 0 {
|
||||||
|
println('cc failed to build v.c without warnings')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
println('v.c can be compiled without warnings. This is good :)')
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
println('Testing...')
|
||||||
|
mut ts := new_test_sesion( args_before_test )
|
||||||
|
ts.files << os.walk_ext(parent_dir, '_test.v')
|
||||||
|
ts.test()
|
||||||
|
println( ts.benchmark.total_message('running V tests') )
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
println('\nBuilding examples...')
|
||||||
|
mut es := new_test_sesion( args_before_test )
|
||||||
|
es.files << os.walk_ext(parent_dir+'/examples','.v').filter(stable_example)
|
||||||
|
es.test()
|
||||||
|
println( es.benchmark.total_message('building examples') )
|
||||||
|
//////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
test_vget()
|
||||||
|
|
||||||
|
if ts.failed || es.failed {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_vget() {
|
||||||
|
/*
|
||||||
|
vexe := os.executable()
|
||||||
|
ret := os.system('$vexe install nedpals.args')
|
||||||
|
if ret != 0 {
|
||||||
|
println('failed to run v install')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
if !os.file_exists(v_modules_path + '/nedpals/args') {
|
||||||
|
println('v failed to install a test module')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
println('vget is OK')
|
||||||
|
*/
|
||||||
|
}
|
Loading…
Reference in New Issue