testing: support for internal module testing

pull/3091/head
Delyan Angelov 2019-12-14 14:57:28 +02:00 committed by Alexander Medvednikov
parent 3a2c46a1ce
commit 1cd5fab21d
8 changed files with 80 additions and 24 deletions

View File

@ -506,23 +506,21 @@ pub fn (v mut V) generate_main() {
if v.table.main_exists() { if v.table.main_exists() {
verror('test files cannot have function `main`') 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') verror('test files need to have at least one test function')
} }
// Generate a C `main`, which calls every single test function // Generate a C `main`, which calls every single test function
v.gen_main_start(false) v.gen_main_start(false)
if v.pref.is_stats { if v.pref.is_stats {
cgen.genln('BenchedTests bt = main__start_testing();') cgen.genln('BenchedTests bt = main__start_testing();')
} }
for tfname in test_fn_names {
for _, f in v.table.fns { if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_start(&bt, tos3("$tfname"));') }
if f.name.starts_with('main__test_') { cgen.genln('$tfname ();')
if v.pref.is_stats { if v.pref.is_stats { cgen.genln('BenchedTests_testing_step_end(&bt);') }
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);') }
}
} }
if v.pref.is_stats { cgen.genln('BenchedTests_end_testing(&bt);') } if v.pref.is_stats { cgen.genln('BenchedTests_end_testing(&bt);') }
v.gen_main_end('return g_test_fails > 0') 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') user_files << filepath.join(preludes_path,'tests_with_stats.v')
} }
// v volt/slack_test.v: compile all .v files to get the environment is_test := dir.ends_with('_test.v')
// I need to implement user packages! TODO mut is_internal_module_test := false
is_test_with_imports := dir.ends_with('_test.v') && if is_test {
(dir.contains('${os.path_separator}volt') || tcontent := os.read_file( dir ) or { panic('$dir does not exist') }
dir.contains('${os.path_separator}c2volt'))// TODO if tcontent.contains('module ') && !tcontent.contains('module main') {
if is_test_with_imports { is_internal_module_test = true
user_files << dir
if pos := dir.last_index(os.path_separator) {
dir = dir[..pos] + os.path_separator// TODO why is this needed
} }
} }
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') { if dir.ends_with('.v') || dir.ends_with('.vsh') {
single_v_file := dir single_v_file := dir
// Just compile one file and get parent dir // Just compile one file and get parent dir

View File

@ -19,7 +19,7 @@ fn cb_assertion_failed(filename string, line int, sourceline string, funcname st
else { true } else { true }
} }
final_filename := if use_relative_paths { filename } else { os.realpath( filename ) } 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' mut fail_message := 'FAILED assertion'
if color_on { fail_message = term.bold(term.red(fail_message)) } if color_on { fail_message = term.bold(term.red(fail_message)) }

View File

@ -34,7 +34,7 @@ fn start_testing() BenchedTests {
// Called before each test_ function, defined in file_test.v // Called before each test_ function, defined in file_test.v
fn (b mut BenchedTests) testing_step_start(stepfunc string) { 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.oks = C.g_test_oks
b.fails = C.g_test_fails b.fails = C.g_test_fails
b.bench.step() b.bench.step()

View File

@ -778,13 +778,14 @@ fn (t &Table) main_exists() bool {
return false 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 { for _, f in t.fns {
if f.name.starts_with('main__test_') { if f.name.contains('__test_') {
return true res << f.name
} }
} }
return false return res
} }
fn (t &Table) find_const(name string) ?Var { fn (t &Table) find_const(name string) ?Var {

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -1,3 +1,5 @@
module main
import os import os
import compiler.tests.repl.runner import compiler.tests.repl.runner
import benchmark import benchmark