|
| 1 | +module main |
| 2 | + |
| 3 | +import time |
| 4 | + |
| 5 | +// Provide a Teamcity implementation of the TestRunner interface. |
| 6 | +// Used in Teamcity and JetBrains IDEs for nice test reporting. |
| 7 | + |
| 8 | +fn vtest_init() { |
| 9 | + change_test_runner(&TestRunner(TeamcityTestRunner{})) |
| 10 | +} |
| 11 | + |
| 12 | +struct TeamcityTestRunner { |
| 13 | +mut: |
| 14 | + fname string |
| 15 | + start_time time.Time |
| 16 | + |
| 17 | + file_test_info VTestFileMetaInfo |
| 18 | + fn_test_info VTestFnMetaInfo |
| 19 | + fn_assert_passes u64 |
| 20 | + fn_passes u64 |
| 21 | + fn_fails u64 |
| 22 | + |
| 23 | + total_assert_passes u64 |
| 24 | + total_assert_fails u64 |
| 25 | +} |
| 26 | + |
| 27 | +fn (mut runner TeamcityTestRunner) free() { |
| 28 | + unsafe { |
| 29 | + runner.fname.free() |
| 30 | + runner.fn_test_info.free() |
| 31 | + runner.file_test_info.free() |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +fn normalise_fname(name string) string { |
| 36 | + return name.replace('__', '.').replace('main.', '') |
| 37 | +} |
| 38 | + |
| 39 | +fn (mut runner TeamcityTestRunner) start(ntests int) { |
| 40 | +} |
| 41 | + |
| 42 | +fn (mut runner TeamcityTestRunner) finish() { |
| 43 | +} |
| 44 | + |
| 45 | +fn (mut runner TeamcityTestRunner) exit_code() int { |
| 46 | + if runner.fn_fails > 0 { |
| 47 | + return 1 |
| 48 | + } |
| 49 | + if runner.total_assert_fails > 0 { |
| 50 | + return 1 |
| 51 | + } |
| 52 | + return 0 |
| 53 | +} |
| 54 | + |
| 55 | +// |
| 56 | + |
| 57 | +fn (mut runner TeamcityTestRunner) fn_start() bool { |
| 58 | + runner.fn_assert_passes = 0 |
| 59 | + runner.start_time = time.now() |
| 60 | + 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 | + return true |
| 64 | +} |
| 65 | + |
| 66 | +fn (mut runner TeamcityTestRunner) fn_pass() { |
| 67 | + runner.fn_passes++ |
| 68 | + duration := runner.test_duration() |
| 69 | + eprintln("##teamcity[testFinished name='${runner.fname}' duration='${duration}']") |
| 70 | + println('\n') |
| 71 | +} |
| 72 | + |
| 73 | +fn (mut runner TeamcityTestRunner) fn_fail() { |
| 74 | + runner.fn_fails++ |
| 75 | + duration := runner.test_duration() |
| 76 | + eprintln("##teamcity[testFailed name='${runner.fname}' duration='${duration}' message='assertion failed']") |
| 77 | + println('\n') |
| 78 | +} |
| 79 | + |
| 80 | +fn (mut runner TeamcityTestRunner) fn_error(line_nr int, file string, mod string, fn_name string, errmsg string) { |
| 81 | + eprintln('>>> TeamcityTestRunner fn_error ${runner.fname}, line_nr: ${line_nr}, file: ${file}, mod: ${mod}, fn_name: ${fn_name}, errmsg: ${errmsg}') |
| 82 | +} |
| 83 | + |
| 84 | +fn (mut runner TeamcityTestRunner) test_duration() i64 { |
| 85 | + return time.now().unix_time_milli() - runner.start_time.unix_time_milli() |
| 86 | +} |
| 87 | + |
| 88 | +// |
| 89 | + |
| 90 | +fn (mut runner TeamcityTestRunner) assert_pass(i &VAssertMetaInfo) { |
| 91 | + runner.total_assert_passes++ |
| 92 | + runner.fn_assert_passes++ |
| 93 | + |
| 94 | + filepath := i.fpath.clone() |
| 95 | + println('>>> assert_pass ${filepath}:${i.line_nr + 1}') |
| 96 | + |
| 97 | + unsafe { i.free() } |
| 98 | +} |
| 99 | + |
| 100 | +fn (mut runner TeamcityTestRunner) assert_fail(i &VAssertMetaInfo) { |
| 101 | + 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() } |
| 136 | +} |
0 commit comments