vxx2 / vlib / v3 / tests / review_checker_regressions_test.v
164 lines · 148 sloc · 8.61 KB · 2b81918e62db9ab38787518603a7f93bee80868c
Raw
1import os
2
3const vexe = @VEXE
4const tests_dir = os.dir(@FILE)
5const v3_dir = os.dir(tests_dir)
6const vlib_dir = os.dir(v3_dir)
7const v3_src = os.join_path(v3_dir, 'v3.v')
8
9fn build_v3_review_checker() string {
10 v3_bin := os.join_path(os.temp_dir(), 'v3_review_checker_regressions_test')
11 build := os.execute('${vexe} -path "${vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${v3_src}')
12 assert build.exit_code == 0, build.output
13 return v3_bin
14}
15
16fn run_bad(v3_bin string, name string, src string, expected string) {
17 bad_src := os.join_path(os.temp_dir(), 'v3_${name}.v')
18 os.write_file(bad_src, src) or { panic(err) }
19 bad_bin := os.join_path(os.temp_dir(), 'v3_${name}')
20 result := os.execute('${v3_bin} ${bad_src} -b c -o ${bad_bin}')
21 assert result.exit_code != 0, '${name}: expected failure, got success\n${result.output}'
22 assert result.output.contains(expected), '${name}: expected `${expected}` in\n${result.output}'
23 assert !result.output.contains('C compilation failed'), '${name}: reached C compilation\n${result.output}'
24}
25
26fn run_good(v3_bin string, name string, src string) string {
27 good_src := os.join_path(os.temp_dir(), 'v3_${name}.v')
28 os.write_file(good_src, src) or { panic(err) }
29 good_bin := os.join_path(os.temp_dir(), 'v3_${name}')
30 compile := os.execute('${v3_bin} ${good_src} -b c -o ${good_bin}')
31 assert compile.exit_code == 0, '${name}: compile failed\n${compile.output}'
32 assert !compile.output.contains('C compilation failed'), '${name}: C compilation failed\n${compile.output}'
33 run := os.execute(good_bin)
34 assert run.exit_code == 0, '${name}: run failed\n${run.output}'
35 return run.output.trim_space()
36}
37
38fn test_reject_pointer_expressions_for_value_returns() {
39 v3_bin := build_v3_review_checker()
40 run_bad(v3_bin, 'bad_return_pointer_to_value',
41 'fn f() int {\n\tx := 1\n\treturn &x\n}\nfn main() {}\n', 'cannot return `&int` as `int`')
42 run_bad(v3_bin, 'bad_result_return_pointer_to_value',
43 'fn f() !int {\n\tx := 1\n\treturn &x\n}\nfn main() {}\n', 'cannot return `&int` as `!int`')
44}
45
46fn test_restrict_synthetic_hex_fallback_receivers() {
47 v3_bin := build_v3_review_checker()
48 run_bad(v3_bin, 'bad_struct_hex_method', 'struct S {}\nfn main() {\n\t_ := S{}.hex()\n}\n',
49 'unknown function')
50 run_bad(v3_bin, 'bad_int_array_hex_method', 'fn main() {\n\t_ := [1, 2].hex()\n}\n',
51 'unknown function')
52 run_bad(v3_bin, 'bad_map_hex_method',
53 'fn main() {\n\tm := map[string]int{}\n\t_ := m.hex()\n}\n', 'unknown function')
54 run_bad(v3_bin, 'bad_float_hex_method', 'fn main() {\n\t_ := f32(1.5).hex()\n}\n',
55 'unknown function')
56 run_bad(v3_bin, 'bad_pointer_hex_method',
57 'fn main() {\n\tx := 1\n\tp := &x\n\t_ := p.hex()\n}\n', 'unknown function')
58 run_bad(v3_bin, 'bad_numeric_hex_arg',
59 'fn side_effect() int {\n\treturn 1\n}\n\nfn main() {\n\t_ := u8(1).hex(side_effect())\n}\n',
60 'argument count mismatch')
61 out := run_good(v3_bin, 'supported_hex_methods',
62 "fn main() {\n\tprintln(u8(15).hex())\n\tprintln(i64(255).hex())\n\tprintln([u8(1), 15, 255].hex())\n\tprintln(char(65).hex())\n\tprintln(`A`.hex())\n\tprintln('abc'.hex())\n}\n")
63 assert out == '0f\nff\n010fff\n41\n41\n616263'
64}
65
66fn test_auto_str_rejects_arguments() {
67 v3_bin := build_v3_review_checker()
68 run_bad(v3_bin, 'bad_auto_str_arg',
69 'struct S {\n\tx int\n}\n\nfn side_effect() int {\n\treturn 1\n}\n\nfn main() {\n\t_ := S{\n\t\tx: 1\n\t}.str(side_effect())\n}\n',
70 'argument count mismatch')
71}
72
73fn test_pointer_hex_receiver_methods_are_allowed() {
74 v3_bin := build_v3_review_checker()
75 out := run_good(v3_bin, 'good_pointer_hex_receiver_method',
76 "struct S {\n\tvalue int\n}\n\nfn (s &S) hex() string {\n\treturn 'ptr:' + int_str(s.value)\n}\n\nfn main() {\n\ts := S{\n\t\tvalue: 7\n\t}\n\tp := &s\n\tprintln(p.hex())\n}\n")
77 assert out == 'ptr:7'
78}
79
80fn test_map_keys_and_values_reject_arguments() {
81 v3_bin := build_v3_review_checker()
82 run_bad(v3_bin, 'bad_map_keys_arg',
83 'fn main() {\n\tm := map[string]int{}\n\t_ := m.keys(123)\n}\n', 'argument count mismatch')
84 run_bad(v3_bin, 'bad_map_values_arg',
85 "fn main() {\n\tm := map[string]int{}\n\t_ := m.values('x')\n}\n",
86 'argument count mismatch')
87}
88
89fn test_array_insert_and_prepend_reject_wrong_arity() {
90 v3_bin := build_v3_review_checker()
91 run_bad(v3_bin, 'bad_array_prepend_missing_arg',
92 'fn main() {\n\tmut a := [1, 2]\n\ta.prepend()\n}\n', 'argument count mismatch')
93 run_bad(v3_bin, 'bad_array_prepend_extra_arg',
94 'fn side_effect() int {\n\treturn 3\n}\nfn main() {\n\tmut a := [1, 2]\n\ta.prepend(0, side_effect())\n}\n',
95 'argument count mismatch')
96 run_bad(v3_bin, 'bad_array_insert_missing_arg',
97 'fn main() {\n\tmut a := [1, 2]\n\ta.insert(0)\n}\n', 'argument count mismatch')
98 run_bad(v3_bin, 'bad_array_insert_extra_arg',
99 'fn side_effect() int {\n\treturn 3\n}\nfn main() {\n\tmut a := [1, 2]\n\ta.insert(0, 1, side_effect())\n}\n',
100 'argument count mismatch')
101 run_bad(v3_bin, 'bad_array_prepend_arg_type',
102 "fn main() {\n\tmut a := [1, 2]\n\ta.prepend('x')\n}\n", 'cannot use')
103 run_bad(v3_bin, 'bad_array_insert_index_type',
104 "fn main() {\n\tmut a := [1, 2]\n\ta.insert('0', 3)\n}\n", 'cannot use')
105 run_bad(v3_bin, 'bad_array_insert_value_type',
106 "fn main() {\n\tmut a := [1, 2]\n\ta.insert(0, 'x')\n}\n", 'cannot use')
107 run_bad(v3_bin, 'bad_array_prepend_many_arg_type',
108 "fn main() {\n\tmut a := [1, 2]\n\ta.prepend(['x'])\n}\n", 'cannot use')
109 run_bad(v3_bin, 'bad_array_insert_many_arg_type',
110 "fn main() {\n\tmut a := [1, 2]\n\ta.insert(0, ['x'])\n}\n", 'cannot use')
111}
112
113fn test_array_insert_and_prepend_accept_many_operands() {
114 v3_bin := build_v3_review_checker()
115 out := run_good(v3_bin, 'good_array_insert_prepend_many_operands',
116 "type Strings = []string\n\nfn main() {\n\tmut a := [3, 4]\n\ta.insert(0, [1, 2])\n\tb := [5, 6]\n\ta.insert(1, b)\n\ta.prepend([0])\n\tfixed := [7, 8]!\n\ta.insert(a.len, fixed)\n\tassert a == [0, 1, 5, 6, 2, 3, 4, 7, 8]\n\tmut strs := Strings(['hi'])\n\tstrs.insert(0, ['there'])\n\tstrs.prepend(['hello'])\n\tassert strs == ['hello', 'there', 'hi']\n\tprintln('ok')\n}\n")
117 assert out == 'ok'
118}
119
120fn test_comptime_if_selected_bodies_are_checked() {
121 v3_bin := build_v3_review_checker()
122 run_bad(v3_bin, 'bad_concrete_comptime_if_selected_call',
123 'fn main() {\n\t$if int is int {\n\t\tmissing_selected_symbol()\n\t}\n}\n',
124 'unknown function `missing_selected_symbol`')
125 out := run_good(v3_bin, 'good_generic_comptime_if_unselected_branch_is_not_checked',
126 "fn ok() {}\n\nfn f[T]() {\n\t$if T is int {\n\t\tok()\n\t} $else {\n\t\tonly_for_other_t()\n\t}\n}\n\nfn main() {\n\tf[int]()\n\tprintln('ok')\n}\n")
127 assert out == 'ok'
128}
129
130fn test_explicit_generic_calls_use_all_type_arguments() {
131 v3_bin := build_v3_review_checker()
132 out := run_good(v3_bin, 'good_multi_explicit_generic_call',
133 "struct Pair[A, B] {\n\tleft A\n\tright B\n}\n\nfn make_pair[A, B]() Pair[A, B] {\n\treturn Pair[A, B]{}\n}\n\nfn expect_pair(p Pair[int, string]) string {\n\treturn 'ok'\n}\n\nfn main() {\n\tp := make_pair[int, string]()\n\tprintln(expect_pair(p))\n}\n")
134 assert out == 'ok'
135 nested := run_good(v3_bin, 'good_nested_explicit_generic_call',
136 "struct Pair[A, B] {\n\tleft A\n\tright B\n}\n\nstruct Box[T] {\n\tvalue T\n}\n\nfn wrap[T]() Box[T] {\n\treturn Box[T]{}\n}\n\nfn expect_box(b Box[Pair[int, string]]) string {\n\treturn 'ok'\n}\n\nfn main() {\n\tb := wrap[Pair[int, string]]()\n\tprintln(expect_box(b))\n}\n")
137 assert nested == 'ok'
138 run_bad(v3_bin, 'bad_explicit_generic_too_many_type_args',
139 'fn id[T](x T) T {\n\treturn x\n}\n\nfn main() {\n\t_ := id[int, string](1)\n}\n',
140 'generic argument count mismatch')
141}
142
143fn test_reject_escaping_capturing_fn_literals() {
144 v3_bin := build_v3_review_checker()
145 run_bad(v3_bin, 'bad_return_capturing_fn_literal',
146 'fn make(x int) fn () int {\n\treturn fn [x] () int {\n\t\treturn x\n\t}\n}\nfn main() {}\n',
147 'capturing fn literal cannot be stored or returned')
148 run_bad(v3_bin, 'bad_store_capturing_fn_literal_alias',
149 'fn main() {\n\tx := 1\n\tf := fn [x] () int {\n\t\treturn x\n\t}\n\tmut cbs := []fn () int{}\n\tcbs << f\n}\n',
150 'capturing fn literal cannot be stored or returned')
151}
152
153fn test_generic_functions_report_missing_return() {
154 v3_bin := build_v3_review_checker()
155 run_bad(v3_bin, 'bad_generic_missing_return', 'fn f[T]() int {\n}\nfn main() {}\n',
156 'missing return at end of function `f`')
157}
158
159fn test_local_identifiers_shadow_module_consts() {
160 v3_bin := build_v3_review_checker()
161 out := run_good(v3_bin, 'good_const_shadowed_by_param_and_local',
162 "const shadowed_value = 'const'\n\nfn param_shadow(shadowed_value int) int {\n\treturn shadowed_value + 1\n}\n\nfn local_shadow() int {\n\tshadowed_value := 2\n\treturn shadowed_value + 1\n}\n\nfn main() {\n\tprintln(int_str(param_shadow(1)))\n\tprintln(int_str(local_shadow()))\n\tprintln(shadowed_value)\n}\n")
163 assert out == '2\n3\nconst'
164}
165