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.
|
||||
s.goto_scanner_position(ScannerPos{})
|
||||
s.file_lines = []string
|
||||
|
||||
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 {
|
||||
prevlinepos = s.pos
|
||||
if s.pos >= s.text.len { break }
|
||||
|
|
129
compiler/main.v
129
compiler/main.v
|
@ -8,7 +8,6 @@ import (
|
|||
os
|
||||
strings
|
||||
benchmark
|
||||
term
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -154,12 +153,12 @@ fn main() {
|
|||
vfmt(args)
|
||||
return
|
||||
}
|
||||
// Construct the V object from command line arguments
|
||||
mut v := new_v(args)
|
||||
if args.join(' ').contains(' test v') {
|
||||
v.test_v()
|
||||
if 'test' in args {
|
||||
test_v()
|
||||
return
|
||||
}
|
||||
// Construct the V object from command line arguments
|
||||
mut v := new_v(args)
|
||||
if v.pref.is_verbose {
|
||||
println(args)
|
||||
}
|
||||
|
@ -741,10 +740,10 @@ fn (v &V) resolve_deps() &DepGraph {
|
|||
}
|
||||
|
||||
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 '
|
||||
mut pos := joined_args.index(key)
|
||||
if pos == -1 {
|
||||
|
@ -756,7 +755,6 @@ fn get_all_after(joined_args, arg, def string) string {
|
|||
space = joined_args.len
|
||||
}
|
||||
res := joined_args.substr(pos, space)
|
||||
// println('get_arg($arg) = "$res"')
|
||||
return res
|
||||
}
|
||||
|
||||
|
@ -777,7 +775,7 @@ fn new_v(args[]string) &V {
|
|||
|
||||
mut dir := args.last()
|
||||
if 'run' in args {
|
||||
dir = get_all_after(joined_args, 'run', '')
|
||||
dir = get_param_after(joined_args, 'run', '')
|
||||
}
|
||||
if dir.ends_with(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() {
|
||||
vexe := os.executable()
|
||||
link_path := '/usr/local/bin/v'
|
||||
|
|
|
@ -46,6 +46,7 @@ Options/commands:
|
|||
Example: -cflags `sdl2-config --cflags`
|
||||
-debug Keep the generated C file for debugging in program.tmp.c even after compilation.
|
||||
-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.
|
||||
-obf Obfuscate the resulting binary.
|
||||
-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.
|
||||
install <module> Install a user module from https://vpm.vlang.io/.
|
||||
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]
|
||||
doc Run vdoc over the source code and produce documentation. [wip]
|
||||
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