Skip to content

Commit 9f7c8ca

Browse files
committed
v3: fix assertion evaluation and stats
1 parent ba2bc16 commit 9f7c8ca

6 files changed

Lines changed: 99 additions & 24 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
V panic: Assertion failed...
2+
vlib/v/slow_tests/inout/v3_assert_operand_once.v3.v:3: assert values.pop() == 0
3+
left value: values.pop() = 1
4+
right value: 0
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fn main() {
2+
mut values := [1]
3+
assert values.pop() == 0
4+
}

vlib/v3/gen/c/cleanc.v

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ mut:
191191
show_test_stats bool
192192
show_test_summary bool
193193
test_run_only []string
194+
assert_expr_overrides map[int]string
194195
print_fn_names []string
195196
is_prod bool
196197
check_overflow bool
@@ -992,6 +993,7 @@ pub fn FlatGen.new() FlatGen {
992993
scope_defer_starts: []int{}
993994
fn_defers: []flat.NodeId{}
994995
fn_defer_counts: map[int]string{}
996+
assert_expr_overrides: map[int]string{}
995997
defer_capture_names: []string{}
996998
defer_capture_types: map[string]types.Type{}
997999
const_runtime_inits: []string{}
@@ -12354,6 +12356,10 @@ fn (mut g FlatGen) gen_expr(id flat.NodeId) {
1235412356
g.write('0')
1235512357
return
1235612358
}
12359+
if replacement := g.assert_expr_overrides[int(id)] {
12360+
g.write(replacement)
12361+
return
12362+
}
1235712363
node := g.a.nodes[int(id)]
1235812364
match node.kind {
1235912365
.int_literal {

vlib/v3/gen/c/fn.v

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ fn (mut g FlatGen) gen_test_failure_global() {
100100
g.writeln('/* V3CACHE_MODULE main */')
101101
}
102102
g.writeln('static int __v3_test_failures = 0;')
103+
if g.show_test_stats {
104+
g.writeln('static int __v3_test_assertions = 0;')
105+
}
103106
}
104107
}
105108

@@ -4523,6 +4526,7 @@ fn (mut g FlatGen) gen_test_main() {
45234526
for idx, test_fn in tests {
45244527
if g.show_test_stats {
45254528
g.writeln('double __v3_test_start_ms_${idx} = __v3_test_now_ms();')
4529+
g.writeln('int __v3_test_assertions_before_${idx} = __v3_test_assertions;')
45264530
}
45274531
g.writeln('int __v3_test_failures_before_${idx} = __v3_test_failures;')
45284532
if hooks.before_each.len > 0 {
@@ -4538,20 +4542,19 @@ fn (mut g FlatGen) gen_test_main() {
45384542
}
45394543
if g.show_test_stats {
45404544
g.writeln('double __v3_test_elapsed_ms_${idx} = __v3_test_now_ms() - __v3_test_start_ms_${idx};')
4545+
g.writeln('int __v3_test_assertions_run_${idx} = __v3_test_assertions - __v3_test_assertions_before_${idx};')
45414546
}
45424547
if track_test_results {
45434548
g.writeln('if (__v3_test_failures == __v3_test_failures_before_${idx}) {')
45444549
g.indent++
45454550
g.writeln('__v3_test_passes++;')
45464551
}
45474552
if g.show_test_stats {
4548-
assert_count := g.test_fn_assert_count(test_fn.node_id)
4549-
assert_word := if assert_count == 1 { 'assert ' } else { 'asserts' }
4550-
g.writeln('printf(" OK [${idx + 1}/${tests.len}] %9.3f ms ${assert_count} ${assert_word} | main.${c_escape(test_fn.name)}()\\n", __v3_test_elapsed_ms_${idx});')
4553+
g.writeln('printf(" OK [${idx + 1}/${tests.len}] %9.3f ms %d assert%s | main.${c_escape(test_fn.name)}()\\n", __v3_test_elapsed_ms_${idx}, __v3_test_assertions_run_${idx}, __v3_test_assertions_run_${idx} == 1 ? "" : "s");')
45514554
g.indent--
45524555
g.writeln('} else {')
45534556
g.indent++
4554-
g.writeln('printf(" FAIL [${idx + 1}/${tests.len}] %9.3f ms ${assert_count} ${assert_word} | main.${c_escape(test_fn.name)}()\\n", __v3_test_elapsed_ms_${idx});')
4557+
g.writeln('printf(" FAIL [${idx + 1}/${tests.len}] %9.3f ms %d assert%s | main.${c_escape(test_fn.name)}()\\n", __v3_test_elapsed_ms_${idx}, __v3_test_assertions_run_${idx}, __v3_test_assertions_run_${idx} == 1 ? "" : "s");')
45554558
}
45564559
if track_test_results {
45574560
g.indent--
@@ -4741,23 +4744,6 @@ fn (g &FlatGen) test_fn_propagation_line(id flat.NodeId) int {
47414744
return 0
47424745
}
47434746

4744-
fn (g &FlatGen) test_fn_assert_count(id flat.NodeId) int {
4745-
if int(id) < 0 || int(id) >= g.a.nodes.len {
4746-
return 0
4747-
}
4748-
node := g.a.nodes[int(id)]
4749-
mut count := if node.kind == .assert_stmt { 1 } else { 0 }
4750-
for i in 0 .. node.children_count {
4751-
child_id := g.a.child(&node, i)
4752-
child := g.a.nodes[int(child_id)]
4753-
if child.kind in [.fn_decl, .c_fn_decl, .fn_literal] {
4754-
continue
4755-
}
4756-
count += g.test_fn_assert_count(child_id)
4757-
}
4758-
return count
4759-
}
4760-
47614747
fn (g &FlatGen) collect_test_harness_decl_ids(node flat.Node, mut ids []flat.NodeId) {
47624748
if node.kind != .file && node.kind != .block {
47634749
return

vlib/v3/gen/c/stmt.v

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,15 +2792,20 @@ fn (mut g FlatGen) gen_node(id flat.NodeId) {
27922792
if g.is_prod {
27932793
return
27942794
}
2795+
condition_id := g.a.child(&node, 0)
2796+
captured_ids := g.gen_assert_capture_numeric_operands(condition_id)
2797+
if g.show_test_stats && g.test_files.len > 0 {
2798+
g.writeln('__v3_test_assertions++;')
2799+
}
27952800
g.write('if (!(')
2796-
g.gen_expr(g.a.child(&node, 0))
2801+
g.gen_expr(condition_id)
27972802
g.writeln(')) {')
27982803
g.indent++
27992804
g.writeln('v3_eprint_lit("V panic: Assertion failed...\\n");')
2800-
if detail := g.assert_failure_detail(node, g.a.child(&node, 0)) {
2805+
if detail := g.assert_failure_detail(node, condition_id) {
28012806
g.writeln('v3_eprint_lit("${c_escape(detail)}\\n");')
28022807
}
2803-
g.gen_assert_infix_values(g.a.child(&node, 0))
2808+
g.gen_assert_infix_values(condition_id)
28042809
if node.children_count > 1 {
28052810
g.write('v3_eprintln_string(')
28062811
g.gen_expr(g.a.child(&node, 1))
@@ -2815,6 +2820,9 @@ fn (mut g FlatGen) gen_node(id flat.NodeId) {
28152820
}
28162821
g.indent--
28172822
g.writeln('}')
2823+
for captured_id in captured_ids {
2824+
g.assert_expr_overrides.delete(captured_id)
2825+
}
28182826
}
28192827
.goto_stmt {
28202828
if g.gen_goto_lock_leaves(node.value) {
@@ -2926,6 +2934,36 @@ fn (mut g FlatGen) gen_assert_infix_values(condition_id flat.NodeId) {
29262934
g.gen_assert_numeric_value(' right value', rhs_id)
29272935
}
29282936

2937+
fn (mut g FlatGen) gen_assert_capture_numeric_operands(condition_id flat.NodeId) []int {
2938+
condition := g.a.node(condition_id)
2939+
if condition.kind != .infix || condition.children_count < 2 {
2940+
return []
2941+
}
2942+
mut captured_ids := []int{cap: 2}
2943+
for operand_index in 0 .. 2 {
2944+
operand_id := g.a.child(condition, operand_index)
2945+
node := g.a.node(operand_id)
2946+
if node.kind in [.int_literal, .float_literal, .char_literal] {
2947+
continue
2948+
}
2949+
typ := g.value_unalias_type(g.tc.resolve_type(operand_id))
2950+
if !typ.is_integer() && !typ.is_float() {
2951+
continue
2952+
}
2953+
c_type := g.value_c_type(g.tc.resolve_type(operand_id))
2954+
if c_type.len == 0 {
2955+
continue
2956+
}
2957+
tmp := g.tmp_name()
2958+
g.write('${c_type} ${tmp} = (${c_type})(')
2959+
g.gen_expr(operand_id)
2960+
g.writeln(');')
2961+
g.assert_expr_overrides[int(operand_id)] = tmp
2962+
captured_ids << int(operand_id)
2963+
}
2964+
return captured_ids
2965+
}
2966+
29292967
fn (mut g FlatGen) gen_assert_numeric_value(prefix string, id flat.NodeId) {
29302968
node := g.a.node(id)
29312969
label := g.assert_source_text(id)

vlib/v3/tests/test_file_harness_codegen_test.v

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,43 @@ fn test_wait() {
131131
assert !summary_line.contains('Elapsed time: 0.000 ms.'), run.output
132132
}
133133

134+
fn test_v3_assertion_operands_run_once_and_stats_count_executed_assertions() {
135+
run_only := os.getenv('VTEST_ONLY_FN')
136+
os.unsetenv('VTEST_ONLY_FN')
137+
defer {
138+
if run_only.len > 0 {
139+
os.setenv('VTEST_ONLY_FN', run_only, true)
140+
}
141+
}
142+
v3_bin := build_v3()
143+
failing_run := compile_and_run(v3_bin, 'assert_operand_once', '_test.v', '
144+
fn test_operand_once() {
145+
mut values := [1]
146+
assert values.pop() == 0
147+
}
148+
')
149+
assert failing_run.exit_code != 0
150+
assert failing_run.output.contains('left value: values.pop() = 1'), failing_run.output
151+
152+
stats_run := compile_and_run_with_stats(v3_bin, 'assert_runtime_count', '_test.v', 'fn helper() {
153+
assert true
154+
}
155+
156+
fn test_runtime_assertion_count() {
157+
for _ in 0 .. 3 {
158+
assert true
159+
}
160+
helper()
161+
if false {
162+
assert false
163+
}
164+
}
165+
')
166+
assert stats_run.exit_code == 0, stats_run.output
167+
status_line := stats_run.output.split_into_lines().filter(it.contains('main.test_runtime_assertion_count()'))[0]
168+
assert status_line.contains('4 asserts |'), stats_run.output
169+
}
170+
134171
fn compile_project_and_run(v3_bin string, name string, files map[string]string) (os.Result, string) {
135172
root := write_project(name, files)
136173
return compile_project_root_and_run(v3_bin, name, root)

0 commit comments

Comments
 (0)