v2 / vlib / v / preludes / test_runner_normal.v
177 lines · 159 sloc · 4.73 KB · 58a3b6f56a43444feffe35dd64d72d104fbfb07c
Raw
1module main
2
3import os
4import term
5
6///////////////////////////////////////////////////////////
7// This file gets compiled as part of the main program, for
8// each _test.v file. It implements the default/normal test
9// output for `v run file_test.v`
10// See also test_runner.c.v .
11///////////////////////////////////////////////////////////
12
13fn vtest_init() {
14 change_test_runner(&TestRunner(new_normal_test_runner()))
15}
16
17struct NormalTestRunner {
18pub mut:
19 fname string
20 use_color bool
21 use_relative_paths bool
22mut:
23 file_test_info VTestFileMetaInfo
24 fn_test_info VTestFnMetaInfo
25 fn_assert_passes u64
26 fn_passes u64
27 fn_fails u64
28
29 total_assert_passes u64
30 total_assert_fails u64
31}
32
33fn new_normal_test_runner() &TestRunner {
34 unsafe {
35 mut tr := &NormalTestRunner{}
36 tr.use_color = term.can_show_color_on_stderr()
37 tr.use_relative_paths = match os.getenv('VERROR_PATHS') {
38 'absolute' { false }
39 else { true }
40 }
41
42 return tr
43 }
44}
45
46fn (mut runner NormalTestRunner) free() {
47 unsafe {
48 runner.fname.free()
49 runner.fn_test_info.free()
50 runner.file_test_info.free()
51 }
52}
53
54fn normalise_fname(name string) string {
55 nt1 := name.replace('__', '.')
56 nt2 := nt1.replace('main.', '')
57 nt3 := 'fn ' + nt2
58 return nt3
59}
60
61fn (mut runner NormalTestRunner) start(_ntests int) {
62}
63
64fn (mut runner NormalTestRunner) finish() {
65}
66
67fn (mut runner NormalTestRunner) exit_code() int {
68 if runner.fn_fails > 0 {
69 return 1
70 }
71 if runner.total_assert_fails > 0 {
72 return 2
73 }
74 return 0
75}
76
77fn (mut runner NormalTestRunner) fn_start() bool {
78 runner.fn_assert_passes = 0
79 runner.fname = normalise_fname(runner.fn_test_info.name)
80 return true
81}
82
83fn (mut runner NormalTestRunner) fn_pass() {
84 runner.fn_passes++
85}
86
87fn (mut runner NormalTestRunner) fn_fail() {
88 runner.fn_fails++
89}
90
91fn (mut runner NormalTestRunner) fn_error(line_nr int, file string, _mod string, fn_name string, errmsg string) {
92 filepath := if runner.use_relative_paths { file.clone() } else { os.real_path(file) }
93 mut final_filepath := filepath + ':${line_nr}:'
94 if runner.use_color {
95 final_filepath = term.gray(final_filepath)
96 }
97 mut final_funcname := 'fn ' + fn_name.replace('main.', '').replace('__', '.')
98 if runner.use_color {
99 final_funcname = term.red('✗ ' + final_funcname)
100 }
101 final_msg := if runner.use_color { term.dim(errmsg) } else { errmsg.clone() }
102 eprintln('${final_filepath} ${final_funcname} failed propagation with error: ${final_msg}')
103 if os.is_file(file) {
104 source_lines := os.read_lines(file) or { []string{len: line_nr + 1} }
105 eprintln('${line_nr:5} | ${source_lines[line_nr - 1]}')
106 }
107}
108
109fn (mut runner NormalTestRunner) assert_pass(_ &VAssertMetaInfo) {
110 runner.total_assert_passes++
111 runner.fn_assert_passes++
112}
113
114fn (mut runner NormalTestRunner) assert_fail(i &VAssertMetaInfo) {
115 runner.total_assert_fails++
116 filepath := if runner.use_relative_paths { i.fpath.clone() } else { os.real_path(i.fpath) }
117 mut final_filepath := filepath + ':${i.line_nr + 1}:'
118 if runner.use_color {
119 final_filepath = term.gray(final_filepath)
120 }
121 mut final_funcname := 'fn ' + i.fn_name.replace('main.', '').replace('__', '.')
122 if runner.use_color {
123 final_funcname = term.red('✗ ' + final_funcname)
124 }
125 final_src := if runner.use_color {
126 term.dim('assert ${term.bold(i.src)}')
127 } else {
128 'assert ' + i.src
129 }
130 eprintln('${final_filepath} ${final_funcname}')
131 if i.op.len > 0 && i.op != 'call' {
132 mut lvtitle := ' Left value (len: ${i.lvalue.len}):'
133 mut rvtitle := ' Right value (len: ${i.rvalue.len}):'
134 mut slvalue := '`${i.lvalue}`'
135 mut srvalue := '`${i.rvalue}`'
136 // Do not print duplicate values to avoid confusion. In mosts tests the developer does
137 // `assert foo() == [1, 2, 3]`
138 // There's no need to print "[1, 2, 3]" again (left: [1,2,3,4] right:[1,2,3])
139 // It makes it harded to understand what is what.
140 // So if "[1,2,3]" is already mentioned in the source, we don't print it.
141 need_to_print_right := !final_src.contains('== ' + srvalue)
142 if runner.use_color {
143 slvalue = term.yellow(slvalue)
144 srvalue = term.yellow(srvalue)
145 lvtitle = term.gray(lvtitle)
146 rvtitle = term.gray(rvtitle)
147 }
148 cutoff_limit := 30
149 if slvalue.len > cutoff_limit || srvalue.len > cutoff_limit {
150 eprintln(' > ${final_src}')
151 eprintln(lvtitle)
152 eprintln(' ${slvalue}')
153 if need_to_print_right {
154 eprintln(rvtitle)
155 eprintln(' ${srvalue}')
156 }
157 } else {
158 eprintln(' > ${final_src}')
159 eprintln(' ${lvtitle} ${slvalue}')
160 if need_to_print_right {
161 eprintln('${rvtitle} ${srvalue}')
162 }
163 }
164 } else {
165 eprintln(' ${final_src}')
166 }
167 if i.has_msg {
168 mut mtitle := ' Message:'
169 mut mvalue := '${i.message}'
170 if runner.use_color {
171 mvalue = term.yellow(mvalue)
172 mtitle = term.gray(mtitle)
173 }
174 eprintln('${mtitle} ${mvalue}')
175 }
176 eprintln('')
177}
178