Skip to content

Commit 6ff953d

Browse files
authored
preludes,builder,cgen: add support for VTEST_RUNNER=tap and -test-runner tap (#12523)
1 parent caac89d commit 6ff953d

28 files changed

+665
-178
lines changed

cmd/tools/test_if_v_test_system_works.v

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,31 @@ fn cleanup_tdir() {
4040
os.rmdir_all(tdir) or { eprintln(err) }
4141
}
4242

43+
fn create_test(tname string, tcontent string) ?string {
44+
tpath := os.join_path(tdir, tname)
45+
os.write_file(tpath, tcontent) ?
46+
eprintln('>>>>>>>> tpath: $tpath | tcontent: $tcontent')
47+
return tpath
48+
}
49+
4350
fn main() {
4451
defer {
4552
os.chdir(os.wd_at_startup) or {}
4653
}
4754
println('> vroot: $vroot | vexe: $vexe | tdir: $tdir')
48-
ok_fpath := os.join_path(tdir, 'single_test.v')
49-
os.write_file(ok_fpath, 'fn test_ok(){ assert true }') ?
50-
check_ok('"$vexe" $ok_fpath')
51-
check_ok('"$vexe" test $ok_fpath')
52-
fail_fpath := os.join_path(tdir, 'failing_test.v')
53-
os.write_file(fail_fpath, 'fn test_fail(){ assert 1 == 2 }') ?
54-
check_fail('"$vexe" $fail_fpath')
55-
check_fail('"$vexe" test $fail_fpath')
56-
check_fail('"$vexe" test $tdir')
55+
ok_fpath := create_test('a_single_ok_test.v', 'fn test_ok(){ assert true }') ?
56+
check_ok('"$vexe" "$ok_fpath"')
57+
check_ok('"$vexe" test "$ok_fpath"')
58+
check_ok('"$vexe" test "$tdir"')
59+
fail_fpath := create_test('a_single_failing_test.v', 'fn test_fail(){ assert 1 == 2 }') ?
60+
check_fail('"$vexe" "$fail_fpath"')
61+
check_fail('"$vexe" test "$fail_fpath"')
62+
check_fail('"$vexe" test "$tdir"')
5763
rel_dir := os.join_path(tdir, rand.ulid())
5864
os.mkdir(rel_dir) ?
5965
os.chdir(rel_dir) ?
60-
check_ok('"$vexe" test ..${os.path_separator + os.base(ok_fpath)}')
66+
check_ok('"$vexe" test "..${os.path_separator + os.base(ok_fpath)}"')
67+
println('> all done')
6168
}
6269

6370
fn check_ok(cmd string) string {

cmd/v/help/test.txt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,23 @@ and then you can perform:
1111
... to run all the module's '_test.v' files.
1212

1313
NB 2: V builtin testing requires you to name your files with a _test.v
14-
suffix, and to name your test functions with test_ prefix. Each 'test_'
15-
function in a '_test.v' file will be called automatically by the test
16-
framework. You can use `assert condition` inside each 'test_' function.
17-
If the asserted condition fails, then v will record that and produce a
18-
more detailed error message about where the failure was.
14+
suffix, and to name your test functions with test_ prefix. Each function,
15+
that starts with 'fn test_', and that is in a '_test.v' file will be called
16+
automatically by the test framework.
17+
18+
NB 3: You can use `assert condition` inside each 'test_' function. If the
19+
asserted condition fails, then v will record that, and produce a more detailed
20+
error message, about where the failure was.
21+
22+
NB 4: Alternative test runners (for IDE integrations):
23+
You can use several alternative test result formats, using `-test-runner name`,
24+
or by setting VTEST_RUNNER (the command line option has higher priority).
25+
26+
The names of the available test runners are:
27+
`simple` Fastest, does not import additional modules, does no processing.
28+
`tap` Format the output as required by the Test Anything Protocol (TAP).
29+
`normal` Supports color output, nicest/most human readable, the default.
30+
31+
You can also implement your own custom test runner, by providing the path to
32+
your .v file, that implements it to this option. For example, see:
33+
vlib/v/preludes/test_runner_tap.v .

vlib/builtin/builtin.c.v

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,25 @@ pub fn eprint(s string) {
173173
}
174174
}
175175

176+
pub fn flush_stdout() {
177+
$if freestanding {
178+
not_implemented := 'flush_stdout is not implemented\n'
179+
bare_eprint(not_implemented.str, u64(not_implemented.len))
180+
} $else {
181+
C.fflush(C.stdout)
182+
}
183+
}
184+
185+
pub fn flush_stderr() {
186+
$if freestanding {
187+
not_implemented := 'flush_stderr is not implemented\n'
188+
bare_eprint(not_implemented.str, u64(not_implemented.len))
189+
} $else {
190+
C.fflush(C.stderr)
191+
}
192+
}
193+
176194
// print prints a message to stdout. Unlike `println` stdout is not automatically flushed.
177-
// A call to `flush()` will flush the output buffer to stdout.
178195
[manualfree]
179196
pub fn print(s string) {
180197
$if android {

vlib/builtin/builtin.v

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ fn __as_cast(obj voidptr, obj_type int, expected_type int) voidptr {
4141
return obj
4242
}
4343

44-
// VAssertMetaInfo is used during assertions. An instance of it
45-
// is filled in by compile time generated code, when an assertion fails.
44+
// VAssertMetaInfo is used during assertions. An instance of it is filled in by
45+
// compile time generated code, when an assertion fails.
4646
pub struct VAssertMetaInfo {
4747
pub:
4848
fpath string // the source file path of the assertion
@@ -56,9 +56,8 @@ pub:
5656
rvalue string // the stringified *actual value* of the right side of a failed assertion
5757
}
5858

59-
// free is used to free the memory occupied by the assertion meta data.
60-
// It is called by cb_assertion_failed, and cb_assertion_ok in the preludes,
61-
// once they are done with reporting/formatting the meta data.
59+
// free frees the memory occupied by the assertion meta data. It is called automatically by
60+
// the code, that V's test framework generates, after all other callbacks have been called.
6261
[manualfree; unsafe]
6362
pub fn (ami &VAssertMetaInfo) free() {
6463
unsafe {

vlib/builtin/map_test.v

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import rand
22

3-
const (
4-
strings = unique_strings(20000, 10)
5-
)
3+
const strings = unique_strings(7000, 10)
64

75
fn unique_strings(arr_len int, str_len int) []string {
86
mut arr := []string{cap: arr_len}
@@ -448,7 +446,7 @@ fn test_map_in() {
448446
'Foo': 'bar'
449447
}
450448
if 'foo'.capitalize() in m {
451-
println('ok')
449+
assert true
452450
} else {
453451
assert false
454452
}

vlib/builtin/sorting_test.v

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ const (
77
fn test_sorting_simple() {
88
mut a := unsorted.clone()
99
a.sort()
10-
eprintln(' a: $a')
10+
println(' a: $a')
1111
assert a == sorted_asc
1212
}
1313

1414
fn test_sorting_with_condition_expression() {
1515
mut a := unsorted.clone()
1616
a.sort(a > b)
17-
eprintln(' a: $a')
17+
println(' a: $a')
1818
assert a == sorted_desc
1919
}
2020

@@ -44,25 +44,25 @@ fn mysort(mut a []int) {
4444
fn test_sorting_by_passing_a_mut_array_to_a_function() {
4545
mut a := unsorted.clone()
4646
mysort(mut a)
47-
eprintln(' a: $a')
47+
println(' a: $a')
4848
assert a == sorted_asc
4949
}
5050

5151
/*
5252
fn test_sorting_by_passing_an_anonymous_sorting_function() {
5353
mut a := unsorted
5454
a.sort(fn(a &int, b &int) int { return *b - *a })
55-
eprintln(' a: $a')
55+
println(' a: $a')
5656
assert a == sort_desc
5757
}
5858
*/
5959
fn test_sorting_u64s() {
6060
mut a := [u64(3), 2, 1, 9, 0, 8]
6161
a.sort()
62-
eprintln(' a: $a')
62+
println(' a: $a')
6363
assert a == [u64(0), 1, 2, 3, 8, 9]
6464
a.sort(a > b)
65-
eprintln(' a: $a')
65+
println(' a: $a')
6666
assert a == [u64(9), 8, 3, 2, 1, 0]
6767
}
6868

vlib/builtin/string.v

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,7 @@ pub fn (s &string) free() {
14441444
return
14451445
}
14461446
unsafe {
1447+
// C.printf(c's: %x %s\n', s.str, s.str)
14471448
free(s.str)
14481449
}
14491450
s.is_lit = -98761234
@@ -1712,8 +1713,8 @@ pub fn (s string) strip_margin() string {
17121713
pub fn (s string) strip_margin_custom(del byte) string {
17131714
mut sep := del
17141715
if sep.is_space() {
1715-
eprintln('Warning: `strip_margin` cannot use white-space as a delimiter')
1716-
eprintln(' Defaulting to `|`')
1716+
println('Warning: `strip_margin` cannot use white-space as a delimiter')
1717+
println(' Defaulting to `|`')
17171718
sep = `|`
17181719
}
17191720
// don't know how much space the resulting string will be, but the max it

vlib/v/ast/table.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub:
9191
is_keep_alive bool // passed memory must not be freed (by GC) before function returns
9292
no_body bool // a pure declaration like `fn abc(x int)`; used in .vh files, C./JS. fns.
9393
mod string
94+
file string
9495
file_mode Language
9596
pos token.Position
9697
return_type_pos token.Position

vlib/v/builder/compile.v

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,24 @@ pub fn (v &Builder) get_user_files() []string {
271271
user_files << os.join_path(preludes_path, 'live_shared.v')
272272
}
273273
if v.pref.is_test {
274-
user_files << os.join_path(preludes_path, 'tests_assertions.v')
274+
user_files << os.join_path(preludes_path, 'test_runner.v')
275+
//
276+
mut v_test_runner_prelude := os.getenv('VTEST_RUNNER')
277+
if v.pref.test_runner != '' {
278+
v_test_runner_prelude = v.pref.test_runner
279+
}
280+
if v_test_runner_prelude == '' {
281+
v_test_runner_prelude = 'normal'
282+
}
283+
if !v_test_runner_prelude.contains('/') && !v_test_runner_prelude.contains('\\')
284+
&& !v_test_runner_prelude.ends_with('.v') {
285+
v_test_runner_prelude = os.join_path(preludes_path, 'test_runner_${v_test_runner_prelude}.v')
286+
}
287+
if !os.is_file(v_test_runner_prelude) || !os.is_readable(v_test_runner_prelude) {
288+
eprintln('test runner error: File $v_test_runner_prelude should be readable.')
289+
verror('supported test runners are: tap, json, simple, normal')
290+
}
291+
user_files << v_test_runner_prelude
275292
}
276293
if v.pref.is_test && v.pref.is_stats {
277294
user_files << os.join_path(preludes_path, 'tests_with_stats.v')

vlib/v/checker/checker.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,9 @@ fn (mut c Checker) fail_if_immutable(expr ast.Expr) (string, token.Position) {
14311431
}
14321432
}
14331433
} else if expr.obj is ast.ConstField && expr.name in c.const_names {
1434-
c.error('cannot modify constant `$expr.name`', expr.pos)
1434+
if !c.inside_unsafe {
1435+
c.error('cannot modify constant `$expr.name`', expr.pos)
1436+
}
14351437
}
14361438
}
14371439
ast.IndexExpr {

0 commit comments

Comments
 (0)