v2 / vlib / v / preludes / test_runner_tap.v
112 lines · 92 sloc · 2.84 KB · 19f080ffb8f8f01976692f6b79d9f857c685e109
Raw
1module main
2
3// TAP, the Test Anything Protocol, is a simple text-based interface
4// between testing modules in a test harness.
5// TAP started life as part of the test harness for Perl but now has
6// implementations in C, C++, Python, PHP, Perl, Java, JavaScript,
7// Go, Rust, and others.
8// Consumers and producers do not have to be written in the same
9// language to interoperate. It decouples the reporting of errors
10// from the presentation of the reports.
11// For more details: https://testanything.org/
12
13// This file implements a TAP producer for V tests.
14// You can use it with:
15// `VTEST_RUNNER=tap v run file_test.v`
16// or
17// `v -test-runner tap run file_test.v`
18
19fn vtest_init() {
20 change_test_runner(&TestRunner(TAPTestRunner{}))
21}
22
23struct TAPTestRunner {
24mut:
25 fname string
26 plan_tests int
27 test_counter int
28
29 file_test_info VTestFileMetaInfo
30 fn_test_info VTestFnMetaInfo
31 fn_assert_passes u64
32 fn_passes u64
33 fn_fails u64
34
35 total_assert_passes u64
36 total_assert_fails u64
37}
38
39fn (mut runner TAPTestRunner) free() {
40 unsafe {
41 runner.fname.free()
42 runner.fn_test_info.free()
43 runner.file_test_info.free()
44 }
45}
46
47fn normalise_fname(name string) string {
48 return 'fn ' + name.replace('__', '.').replace('main.', '')
49}
50
51fn flush_println(s string) {
52 println(s)
53 flush_stdout()
54}
55
56fn (mut runner TAPTestRunner) start(ntests int) {
57 runner.plan_tests = ntests
58 flush_println('1..${ntests}')
59}
60
61fn (mut runner TAPTestRunner) finish() {
62 flush_println('# ${runner.plan_tests} tests, ${runner.total_assert_fails +
63 runner.total_assert_passes} assertions, ${runner.total_assert_fails} failures')
64}
65
66fn (mut runner TAPTestRunner) exit_code() int {
67 if runner.fn_fails > 0 {
68 return 1
69 }
70 if runner.total_assert_fails > 0 {
71 return 2
72 }
73 return 0
74}
75
76//
77
78fn (mut runner TAPTestRunner) fn_start() bool {
79 runner.fn_assert_passes = 0
80 runner.test_counter++
81 runner.fname = normalise_fname(runner.fn_test_info.name)
82 return true
83}
84
85fn (mut runner TAPTestRunner) fn_pass() {
86 runner.fn_passes++
87 flush_println('ok ${runner.test_counter} - ${runner.fname}')
88}
89
90fn (mut runner TAPTestRunner) fn_fail() {
91 flush_println('not ok ${runner.test_counter} - ${runner.fname}')
92 runner.fn_fails++
93}
94
95fn (mut runner TAPTestRunner) fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) {
96 flush_println('# test function propagated error: ${runner.fname}, line_nr: ${line_nr}, file: ${file}, mod: ${mod}, fn_name: ${fn_name}, errmsg: ${errmsg}')
97}
98
99//
100
101fn (mut runner TAPTestRunner) assert_pass(i &VAssertMetaInfo) {
102 runner.total_assert_passes++
103 runner.fn_assert_passes++
104 unsafe { i.free() }
105}
106
107fn (mut runner TAPTestRunner) assert_fail(i &VAssertMetaInfo) {
108 runner.total_assert_fails++
109 flush_println('# failed assert: ${runner.fn_assert_passes + 1} in ${runner.fname}, assert was in ${normalise_fname(i.fn_name)}, line: ${
110 i.line_nr + 1}')
111 unsafe { i.free() }
112}
113