From 1cd5fab21db9776898abcfc100059bfd0ffe36b0 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 14 Dec 2019 14:57:28 +0200 Subject: [PATCH] testing: support for internal module testing --- vlib/compiler/main.v | 42 +++++++++++-------- vlib/compiler/preludes/tests_assertions.v | 2 +- vlib/compiler/preludes/tests_with_stats.v | 2 +- vlib/compiler/table.v | 9 ++-- .../amodule/another_internal_module_test.v | 16 +++++++ .../modules/amodule/internal_module_test.v | 16 +++++++ vlib/compiler/tests/modules/amodule/module.v | 15 +++++++ vlib/compiler/tests/repl/repl_test.v | 2 + 8 files changed, 80 insertions(+), 24 deletions(-) create mode 100644 vlib/compiler/tests/modules/amodule/another_internal_module_test.v create mode 100644 vlib/compiler/tests/modules/amodule/internal_module_test.v create mode 100644 vlib/compiler/tests/modules/amodule/module.v diff --git a/vlib/compiler/main.v b/vlib/compiler/main.v index 79a5734ec1..582fb04704 100644 --- a/vlib/compiler/main.v +++ b/vlib/compiler/main.v @@ -506,23 +506,21 @@ pub fn (v mut V) generate_main() { if v.table.main_exists() { verror('test files cannot have function `main`') } - if !v.table.has_at_least_one_test_fn() { + test_fn_names := v.table.all_test_function_names() + if test_fn_names.len == 0 { verror('test files need to have at least one test function') } + // Generate a C `main`, which calls every single test function v.gen_main_start(false) if v.pref.is_stats { cgen.genln('BenchedTests bt = main__start_testing();') } - - for _, f in v.table.fns { - if f.name.starts_with('main__test_') { - if v.pref.is_stats { - cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$f.name"));') } - cgen.genln('$f.name ();') - if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_end(&bt);') } - } + for tfname in test_fn_names { + if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$tfname"));') } + cgen.genln('$tfname ();') + if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_end(&bt);') } } if v.pref.is_stats { cgen.genln('BenchedTests_end_testing(&bt);') } v.gen_main_end('return g_test_fails > 0') @@ -766,17 +764,25 @@ pub fn (v &V) get_user_files() []string { user_files << filepath.join(preludes_path,'tests_with_stats.v') } - // v volt/slack_test.v: compile all .v files to get the environment - // I need to implement user packages! TODO - is_test_with_imports := dir.ends_with('_test.v') && - (dir.contains('${os.path_separator}volt') || - dir.contains('${os.path_separator}c2volt'))// TODO - if is_test_with_imports { - user_files << dir - if pos := dir.last_index(os.path_separator) { - dir = dir[..pos] + os.path_separator// TODO why is this needed + is_test := dir.ends_with('_test.v') + mut is_internal_module_test := false + if is_test { + tcontent := os.read_file( dir ) or { panic('$dir does not exist') } + if tcontent.contains('module ') && !tcontent.contains('module main') { + is_internal_module_test = true } } + if is_internal_module_test { + // v volt/slack_test.v: compile all .v files to get the environment + single_test_v_file := os.realpath(dir) + if v.pref.is_verbose { + v.log('> Compiling an internal module _test.v file $single_test_v_file .') + v.log('> That brings in all other ordinary .v files in the same module too .') + } + user_files << single_test_v_file + dir = os.basedir( single_test_v_file ) + } + if dir.ends_with('.v') || dir.ends_with('.vsh') { single_v_file := dir // Just compile one file and get parent dir diff --git a/vlib/compiler/preludes/tests_assertions.v b/vlib/compiler/preludes/tests_assertions.v index 306145f488..d1688715a6 100644 --- a/vlib/compiler/preludes/tests_assertions.v +++ b/vlib/compiler/preludes/tests_assertions.v @@ -19,7 +19,7 @@ fn cb_assertion_failed(filename string, line int, sourceline string, funcname st else { true } } final_filename := if use_relative_paths { filename } else { os.realpath( filename ) } - final_funcname := funcname.replace('main__','') + final_funcname := funcname.replace('main__','').replace('__','.') mut fail_message := 'FAILED assertion' if color_on { fail_message = term.bold(term.red(fail_message)) } diff --git a/vlib/compiler/preludes/tests_with_stats.v b/vlib/compiler/preludes/tests_with_stats.v index daf9597b73..2440d66b58 100644 --- a/vlib/compiler/preludes/tests_with_stats.v +++ b/vlib/compiler/preludes/tests_with_stats.v @@ -34,7 +34,7 @@ fn start_testing() BenchedTests { // Called before each test_ function, defined in file_test.v fn (b mut BenchedTests) testing_step_start(stepfunc string) { - b.step_func_name = stepfunc.replace('main__','') + b.step_func_name = stepfunc.replace('main__','').replace('__','.') b.oks = C.g_test_oks b.fails = C.g_test_fails b.bench.step() diff --git a/vlib/compiler/table.v b/vlib/compiler/table.v index 36932a9d37..fa39d0493e 100644 --- a/vlib/compiler/table.v +++ b/vlib/compiler/table.v @@ -778,13 +778,14 @@ fn (t &Table) main_exists() bool { return false } -fn (t &Table) has_at_least_one_test_fn() bool { +fn (t &Table) all_test_function_names() []string { + mut res := []string for _, f in t.fns { - if f.name.starts_with('main__test_') { - return true + if f.name.contains('__test_') { + res << f.name } } - return false + return res } fn (t &Table) find_const(name string) ?Var { diff --git a/vlib/compiler/tests/modules/amodule/another_internal_module_test.v b/vlib/compiler/tests/modules/amodule/another_internal_module_test.v new file mode 100644 index 0000000000..06fd3951ac --- /dev/null +++ b/vlib/compiler/tests/modules/amodule/another_internal_module_test.v @@ -0,0 +1,16 @@ +module amodule + +// This tests whether _test.v files can be *internal* to a +// module, and thus have access to its guts. + +// NB: the function test_private_isub() is defined both here +// and inside internal_module_test.v . That is done on purpose, +// with the goal of ensuring that _test.v files are compiled +// *independently* from each other. +// +// _test.v files should *only* import all the other normal .v +// files from the same folder, NOT other _test.v files from it. + +fn test_private_isub(){ + assert private_isub(7,5) == 2 +} diff --git a/vlib/compiler/tests/modules/amodule/internal_module_test.v b/vlib/compiler/tests/modules/amodule/internal_module_test.v new file mode 100644 index 0000000000..2064895007 --- /dev/null +++ b/vlib/compiler/tests/modules/amodule/internal_module_test.v @@ -0,0 +1,16 @@ +module amodule + +// this tests whether _test.v files can be *internal* +// to a module, and thus have access to its guts. + +fn test_iadd(){ + assert iadd(10, 20) == 30 +} + +fn test_imul(){ + assert imul(5,8) == 40 +} + +fn test_private_isub(){ + assert private_isub(10,6) == 4 +} diff --git a/vlib/compiler/tests/modules/amodule/module.v b/vlib/compiler/tests/modules/amodule/module.v new file mode 100644 index 0000000000..f2742b4e73 --- /dev/null +++ b/vlib/compiler/tests/modules/amodule/module.v @@ -0,0 +1,15 @@ +module amodule + +pub fn iadd(x int, y int) int { + return x + y +} + +pub fn imul(x int, y int) int { + return x * y +} + +/////////////////////////////////////// + +fn private_isub(x int, y int) int { + return x - y +} diff --git a/vlib/compiler/tests/repl/repl_test.v b/vlib/compiler/tests/repl/repl_test.v index 21160c3159..1940fcc9a1 100644 --- a/vlib/compiler/tests/repl/repl_test.v +++ b/vlib/compiler/tests/repl/repl_test.v @@ -1,3 +1,5 @@ +module main + import os import compiler.tests.repl.runner import benchmark