Skip to content

Commit 04cb6ae

Browse files
author
Makhnev Petr
authored
tests: improve Teamcity test runner (#16817)
1 parent 1e401d1 commit 04cb6ae

File tree

1 file changed

+86
-38
lines changed

1 file changed

+86
-38
lines changed

vlib/v/preludes/test_runner_teamcity.v

Lines changed: 86 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module main
22

33
import time
4+
import term
45

56
// Provide a Teamcity implementation of the TestRunner interface.
67
// Used in Teamcity and JetBrains IDEs for nice test reporting.
@@ -20,6 +21,7 @@ mut:
2021
fn_passes u64
2122
fn_fails u64
2223

24+
assertion_info VAssertMetaInfo
2325
total_assert_passes u64
2426
total_assert_fails u64
2527
}
@@ -58,25 +60,94 @@ fn (mut runner TeamcityTestRunner) fn_start() bool {
5860
runner.fn_assert_passes = 0
5961
runner.start_time = time.now()
6062
runner.fname = normalise_fname(runner.fn_test_info.name)
61-
println("Start '${runner.fname}'")
62-
eprintln("##teamcity[testStarted name='${runner.fname}' locationHint='v_qn://${runner.file_test_info.file}:${runner.fname}']")
63+
64+
msg := "Start '${runner.fname}' test"
65+
println(term.gray(msg))
66+
67+
runner.print_service("
68+
|##teamcity[
69+
|testStarted name='${runner.fname}'
70+
|locationHint='v_qn://${runner.file_test_info.file}:${runner.fname}'
71+
|]".strip_margin())
6372
return true
6473
}
6574

6675
fn (mut runner TeamcityTestRunner) fn_pass() {
6776
runner.fn_passes++
6877
duration := runner.test_duration()
6978
eprintln("##teamcity[testFinished name='${runner.fname}' duration='${duration}']")
79+
end_msg := "Finish '${runner.fname}' test"
80+
println(term.gray(end_msg))
81+
msg := "Test '${runner.fname}' passed"
82+
println(term.green(msg))
7083
println('\n')
7184
}
7285

7386
fn (mut runner TeamcityTestRunner) fn_fail() {
7487
runner.fn_fails++
7588
duration := runner.test_duration()
76-
eprintln("##teamcity[testFailed name='${runner.fname}' duration='${duration}' message='assertion failed']")
89+
assertion := runner.assertion_info
90+
91+
mut actual := runner.prepare_value(assertion.lvalue)
92+
mut expected := runner.prepare_value(assertion.rvalue)
93+
94+
message := if assertion.has_msg {
95+
'Assertion "${assertion.message}" failed'
96+
} else {
97+
op := if assertion.op == '' { '' } else { assertion.op }
98+
99+
if op == 'in' {
100+
parts := assertion.src.split('in')
101+
if parts.len == 2 {
102+
left := parts[0].trim(' ')
103+
right := parts[1].trim(' ')
104+
'Assertion that "${left}" in "${right}" failed'
105+
} else {
106+
'Assertion "${assertion.src}" failed'
107+
}
108+
} else if op == 'is' {
109+
'Assertion that left and right type are equal failed'
110+
} else if op == 'call' {
111+
actual = 'false'
112+
expected = 'true'
113+
'Assertion that function call "${assertion.src}" returns true failed'
114+
} else {
115+
lines := assertion.src.split_into_lines()
116+
if lines.len == 1 {
117+
'Assertion "${lines.first()}" failed'
118+
} else {
119+
'Assertion failed'
120+
}
121+
}
122+
}
123+
124+
details := 'See failed assertion: ${assertion.fpath}:${assertion.line_nr + 1}'
125+
126+
runner.print_service("
127+
|##teamcity[
128+
|testFailed name='${runner.fname}'
129+
|duration='${duration}'
130+
|details='${details}'
131+
|type='comparisonFailure'
132+
|actual='${actual}'
133+
|expected='${expected}'
134+
|message='${message}'
135+
|]".strip_margin())
77136
println('\n')
78137
}
79138

139+
// prepare_value escapes the value for Teamcity output.
140+
// For example, it replaces `\n` with `|n`, otherwise Teamcity
141+
// will not correctly parse the output.
142+
fn (mut _ TeamcityTestRunner) prepare_value(raw string) string {
143+
return raw
144+
.replace('\n', '|n')
145+
.replace('\r', '|r')
146+
.replace('[', '|[')
147+
.replace(']', '|]')
148+
.replace("'", "|'")
149+
}
150+
80151
fn (mut runner TeamcityTestRunner) fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) {
81152
eprintln('>>> TeamcityTestRunner fn_error ${runner.fname}, line_nr: ${line_nr}, file: ${file}, mod: ${mod}, fn_name: ${fn_name}, errmsg: ${errmsg}')
82153
}
@@ -85,52 +156,29 @@ fn (mut runner TeamcityTestRunner) test_duration() i64 {
85156
return time.now().unix_time_milli() - runner.start_time.unix_time_milli()
86157
}
87158

159+
// print_service prepare and prints a Teamcity service message.
160+
fn (mut runner TeamcityTestRunner) print_service(msg string) {
161+
without_new_lines := msg
162+
.trim('\n\r ')
163+
.replace('\r', '')
164+
.replace('\n', ' ')
165+
eprintln(without_new_lines)
166+
}
167+
88168
//
89169

90170
fn (mut runner TeamcityTestRunner) assert_pass(i &VAssertMetaInfo) {
91171
runner.total_assert_passes++
92172
runner.fn_assert_passes++
93173

94174
filepath := i.fpath.clone()
95-
println('>>> assert_pass ${filepath}:${i.line_nr + 1}')
175+
msg := '>>> assertion passed ${filepath}:${i.line_nr + 1}'
176+
println(term.green(msg))
96177

97178
unsafe { i.free() }
98179
}
99180

100181
fn (mut runner TeamcityTestRunner) assert_fail(i &VAssertMetaInfo) {
101182
runner.total_assert_fails++
102-
103-
filepath := i.fpath.clone()
104-
mut final_filepath := filepath + ':${i.line_nr + 1}:'
105-
mut final_funcname := 'fn ' + i.fn_name.replace('main.', '').replace('__', '.')
106-
final_src := 'assert ' + i.src
107-
eprintln('${final_filepath} ${final_funcname}')
108-
if i.op.len > 0 && i.op != 'call' {
109-
mut lvtitle := ' Left value:'
110-
mut rvtitle := ' Right value:'
111-
mut slvalue := '${i.lvalue}'
112-
mut srvalue := '${i.rvalue}'
113-
cutoff_limit := 30
114-
if slvalue.len > cutoff_limit || srvalue.len > cutoff_limit {
115-
eprintln(' > ${final_src}')
116-
eprintln(lvtitle)
117-
eprintln(' ${slvalue}')
118-
eprintln(rvtitle)
119-
eprintln(' ${srvalue}')
120-
} else {
121-
eprintln(' > ${final_src}')
122-
eprintln(' ${lvtitle} ${slvalue}')
123-
eprintln('${rvtitle} ${srvalue}')
124-
}
125-
} else {
126-
eprintln(' ${final_src}')
127-
}
128-
if i.has_msg {
129-
mut mtitle := ' Message:'
130-
mut mvalue := '${i.message}'
131-
eprintln('${mtitle} ${mvalue}')
132-
}
133-
eprintln('')
134-
135-
unsafe { i.free() }
183+
runner.assertion_info = *i
136184
}

0 commit comments

Comments
 (0)