vxx2 / vlib / v3 / tests / post_merge_review_fixes_test.v
344 lines · 319 sloc · 21.78 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 repo_dir = os.dir(vlib_dir)
8const v3_src = os.join_path(v3_dir, 'v3.v')
9const compiler_src_dir = os.join_path(repo_dir, 'cmd', 'v')
10
11fn tmp_test_path(name string) string {
12 return os.join_path(os.temp_dir(), 'v3_${name}_${os.getpid()}')
13}
14
15fn build_v3() string {
16 v3_bin := tmp_test_path('post_merge_review_fixes_test')
17 build :=
18 os.execute('${vexe} -gc none -path "${vlib_dir}|@vlib|@vmodules" -o ${v3_bin} ${v3_src}')
19 assert build.exit_code == 0, build.output
20 return v3_bin
21}
22
23fn run_good(v3_bin string, name string, src string) string {
24 good_src := '${tmp_test_path(name)}.v'
25 os.write_file(good_src, src) or { panic(err) }
26 good_bin := tmp_test_path(name)
27 compile := os.execute('${v3_bin} ${good_src} -b c -o ${good_bin}')
28 assert compile.exit_code == 0, compile.output
29 assert !compile.output.contains('C compilation failed'), compile.output
30 run := os.execute(good_bin)
31 assert run.exit_code == 0, run.output
32 return run.output.trim_space()
33}
34
35fn run_bad(v3_bin string, name string, src string, expected string) {
36 bad_src := '${tmp_test_path(name)}.v'
37 os.write_file(bad_src, src) or { panic(err) }
38 bad_bin := tmp_test_path(name)
39 compile := os.execute('${v3_bin} ${bad_src} -b c -o ${bad_bin}')
40 assert compile.exit_code != 0, compile.output
41 assert compile.output.contains(expected), compile.output
42 assert !compile.output.contains('C compilation failed'), compile.output
43}
44
45fn gen_c(v3_bin string, name string, src string) string {
46 src_path := '${tmp_test_path(name)}.v'
47 os.write_file(src_path, src) or { panic(err) }
48 c_path := '${tmp_test_path(name)}.c'
49 os.rm(c_path) or {}
50 compile := os.execute('${v3_bin} ${src_path} -b c -o ${c_path}')
51 assert compile.exit_code == 0, compile.output
52 assert os.exists(c_path)
53 return os.read_file(c_path) or { panic(err) }
54}
55
56fn write_project_file(root string, rel string, src string) {
57 path := os.join_path(root, rel)
58 os.mkdir_all(os.dir(path)) or { panic(err) }
59 os.write_file(path, src) or { panic(err) }
60}
61
62fn run_good_project(v3_bin string, name string, files map[string]string, input string) string {
63 root := '${tmp_test_path(name)}_project'
64 if os.exists(root) {
65 os.rmdir_all(root) or { panic(err) }
66 }
67 os.mkdir_all(root) or { panic(err) }
68 for rel, src in files {
69 write_project_file(root, rel, src)
70 }
71 input_path := if input.len == 0 { root } else { os.join_path(root, input) }
72 good_bin := tmp_test_path(name)
73 compile := os.execute('${v3_bin} ${input_path} -b c -o ${good_bin}')
74 assert compile.exit_code == 0, compile.output
75 assert !compile.output.contains('C compilation failed'), compile.output
76 run := os.execute(good_bin)
77 assert run.exit_code == 0, run.output
78 return run.output.trim_space()
79}
80
81fn test_compiler_vexe_env_uses_running_executable() {
82 v3_bin := build_v3()
83 c_out := os.join_path(os.temp_dir(), 'v3_review_vexe.c')
84 os.rm(c_out) or {}
85 gen := os.execute('${v3_bin} -o ${c_out} ${compiler_src_dir}')
86 assert gen.exit_code == 0, gen.output
87 assert os.exists(c_out)
88 c_source := os.read_file(c_out) or { panic(err) }
89 assert !c_source.contains('v3_vexe_target')
90 assert !c_source.contains('fopen(v3_src')
91 assert c_source.contains('snprintf(v3_checkout_vexe, sizeof(v3_checkout_vexe),')
92 assert c_source.contains('if (access(v3_checkout_vexe, F_OK) == 0) v3_vexe = v3_checkout_vexe;')
93 assert c_source.contains('const char* v3_vexe = v3_src_real_result != NULL ? v3_src_real : v3_arg0;')
94 assert c_source.contains('_putenv_s("VEXE", v3_vexe);')
95 assert c_source.contains('setenv("VEXE", v3_vexe, 1);')
96}
97
98fn test_filelock_helpers_are_inlined_in_generated_c() {
99 v3_bin := build_v3()
100 c_source := gen_c(v3_bin, 'filelock_helpers_inline',
101 'import os.filelock\n\nfn C.v_filelock_lock(i32, i32, i32, u64, u64) i32\nfn C.v_filelock_unlock(i32, u64, u64) i32\n\nfn main() {\n\t_ = filelock.LockMode.exclusive\n\t_ = C.v_filelock_lock(i32(-1), 1, 1, u64(0), u64(0))\n\t_ = C.v_filelock_unlock(i32(-1), u64(0), u64(0))\n}\n')
102 assert !c_source.contains('filelock_helpers.h')
103 assert c_source.contains('static inline int v_filelock_lock(')
104 assert c_source.contains('static inline int v_filelock_unlock(')
105 assert c_source.contains('#ifndef V_OS_FILELOCK_HELPERS_H')
106 assert !c_source.contains('v_filelock_status')
107 status_source := gen_c(v3_bin, 'filelock_custom_prefix_decl',
108 'import os.filelock\n\nfn C.v_filelock_lock(i32, i32, i32, u64, u64) i32\nfn C.v_filelock_unlock(i32, u64, u64) i32\nfn C.v_filelock_status() int\n\nfn main() {\n\t_ = filelock.LockMode.exclusive\n\t_ = C.v_filelock_lock(i32(-1), 1, 1, u64(0), u64(0))\n\t_ = C.v_filelock_status()\n}\n')
109 assert status_source.contains('int v_filelock_status(')
110 out := run_good(v3_bin, 'filelock_user_names_not_helpers',
111 'fn v_filelock_lock() int {\n\treturn 3\n}\n\nfn v_filelock_unlock() int {\n\treturn 4\n}\n\nfn main() {\n\tprintln(int_str(v_filelock_lock() + v_filelock_unlock()))\n}\n')
112 assert out == '7'
113}
114
115fn test_assoc_return_runs_defers() {
116 v3_bin := build_v3()
117 out := run_good(v3_bin, 'assoc_return_runs_defers',
118 'struct Point {\n\tx int\n\ty int\n}\n\n__global hit int\n\nfn make_point() Point {\n\tbase := Point{\n\t\tx: 1\n\t\ty: 2\n\t}\n\tdefer {\n\t\thit = 7\n\t}\n\treturn Point{\n\t\t...base\n\t\tx: 5\n\t}\n}\n\nfn main() {\n\tp := make_point()\n\tprintln(int_str(p.x))\n\tprintln(int_str(hit))\n}\n')
119 assert out == '5\n7'
120}
121
122fn test_pointer_arithmetic_deref_keeps_pointer_type() {
123 v3_bin := build_v3()
124 out := run_good(v3_bin, 'pointer_arithmetic_deref',
125 'fn main() {\n\tmut nums := [1, 2]!\n\tp := unsafe { &nums[0] }\n\tv := unsafe { *(p + 1) }\n\tprintln(int_str(v))\n}\n')
126 assert out == '2'
127}
128
129fn test_array_alias_free_uses_array_builtin_inside_alias_method() {
130 v3_bin := build_v3()
131 out := run_good(v3_bin, 'array_alias_free_builtin',
132 'import strings\n\nfn main() {\n\tmut b := strings.new_builder(4)\n\tb.write_string("ok")\n\tunsafe { b.free() }\n\tprintln("ok")\n}\n')
133 assert out == 'ok'
134}
135
136fn test_channel_alias_close_method_wins_over_builtin() {
137 v3_bin := build_v3()
138 out := run_good(v3_bin, 'channel_alias_close_method_before_builtin',
139 'type MyChan = chan int\n\nfn (c MyChan) close() int {\n\treturn 71\n}\n\nfn main() {\n\tch := MyChan(unsafe { nil })\n\tprintln(int_str(ch.close()))\n}\n')
140 assert out == '71'
141 pointer_c := gen_c(v3_bin, 'pointer_channel_close_lowers_to_runtime',
142 'fn main() {\n\tmut ch := chan bool{cap: 1}\n\tp := &ch\n\tp.close()\n}\n')
143 assert pointer_c.contains('sync__Channel__close(*p,')
144}
145
146fn test_qualified_enum_str_requires_exact_receiver() {
147 v3_bin := build_v3()
148 out := run_good_project(v3_bin, 'qualified_enum_str_exact_receiver', {
149 'main.v': 'module main\n\nimport moda\nimport modb\n\nfn main() {\n\tprintln(moda.Color.red.str())\n\tprintln(modb.Color.blue.str())\n}\n'
150 'moda/moda.v': 'module moda\n\npub enum Color {\n\tred\n}\n'
151 'modb/modb.v': "module modb\n\npub enum Color {\n\tblue\n}\n\npub fn (c Color) str() string {\n\treturn 'custom'\n}\n"
152 }, 'main.v')
153 assert out == 'red\ncustom'
154}
155
156fn test_array_builtin_method_fallback_keeps_return_type() {
157 v3_bin := build_v3()
158 out := run_good(v3_bin, 'array_builtin_method_fallback',
159 'fn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tnums << 2\n\tnums << 3\n\tptrs := unsafe { nums.pointers() }\n\tprintln(int_str(ptrs.len))\n}\n')
160 assert out == '3'
161 ptr_out := run_good(v3_bin, 'array_pointers_pointer_receiver',
162 'fn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tp := &nums\n\tptrs := unsafe { p.pointers() }\n\tprintln(int_str(ptrs.len))\n}\n')
163 assert ptr_out == '1'
164 reverse_out := run_good(v3_bin, 'array_reverse_pointer_receiver',
165 'fn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tnums << 2\n\tp := &nums\n\tp.reverse()\n\tprintln("ok")\n}\n')
166 assert reverse_out == 'ok'
167 exact_out := run_good(v3_bin, 'exact_array_receiver_method_before_builtin',
168 'fn (a []int) pointers() []int {\n\treturn a\n}\n\nfn main() {\n\tnums := [9]\n\tptrs := nums.pointers()\n\tprintln(int_str(ptrs[0]))\n}\n')
169 assert exact_out == '9'
170 exact_clear_out := run_good(v3_bin, 'exact_array_clear_method_before_cgen',
171 'fn (a []int) clear() int {\n\treturn 5\n}\n\nfn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tprintln(int_str(nums.clear()))\n\tprintln(int_str(nums.len))\n}\n')
172 assert exact_clear_out == '5\n1'
173 exact_clone_out := run_good(v3_bin, 'exact_array_clone_method_before_builtin',
174 'fn (a []int) clone() int {\n\treturn 12\n}\n\nfn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tprintln(int_str(nums.clone()))\n}\n')
175 assert exact_clone_out == '12'
176 exact_reverse_out := run_good(v3_bin, 'exact_array_reverse_method_before_builtin',
177 'fn (a []int) reverse() int {\n\treturn 13\n}\n\nfn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tprintln(int_str(nums.reverse()))\n}\n')
178 assert exact_reverse_out == '13'
179 module_array_prefix_out := run_good_project(v3_bin, 'array_prefix_module_receiver_method', {
180 'main.v': 'module main\n\nimport array_utils\n\nfn main() {\n\tprintln(array_utils.run())\n}\n'
181 'array_utils/mod.v': 'module array_utils\n\nfn (a []int) reverse() int {\n\treturn 73\n}\n\npub fn run() string {\n\tmut nums := []int{}\n\tnums << 1\n\treturn int_str(nums.reverse())\n}\n'
182 }, 'main.v')
183 assert module_array_prefix_out == '73'
184 module_array_runtime_prefix_out := run_good_project(v3_bin,
185 'array_runtime_prefix_module_receiver_method', {
186 'main.v': 'module main\n\nimport array__utils\n\nfn main() {\n\tprintln(array__utils.run())\n}\n'
187 'array__utils/mod.v': 'module array__utils\n\nfn (a []int) reverse() int {\n\treturn 83\n}\n\npub fn run() string {\n\tmut nums := []int{}\n\tnums << 1\n\treturn int_str(nums.reverse())\n}\n'
188 }, 'main.v')
189 assert module_array_runtime_prefix_out == '83'
190 module_array_move_out := run_good_project(v3_bin, 'module_array_move_receiver_method', {
191 'main.v': 'module main\n\nimport thing\n\nfn main() {\n\tprintln(thing.run())\n}\n'
192 'thing/mod.v': 'module thing\n\nfn (a []int) move() int {\n\treturn 91\n}\n\npub fn run() string {\n\tmut nums := []int{}\n\tnums << 1\n\treturn int_str(nums.move())\n}\n'
193 }, 'main.v')
194 assert module_array_move_out == '91'
195 exact_prepend_out := run_good(v3_bin, 'exact_array_prepend_method_before_builtin',
196 'fn (a []int) prepend(x int) int {\n\treturn x + 1\n}\n\nfn main() {\n\tmut nums := []int{}\n\tnums << 1\n\tprintln(int_str(nums.prepend(4)))\n}\n')
197 assert exact_prepend_out == '5'
198 run_bad(v3_bin, 'exact_array_first_method_checked_before_builtin',
199 'fn (a []int) first() string {\n\treturn "bad"\n}\n\nfn take_int(x int) {}\n\nfn main() {\n\tmut nums := []int{}\n\tnums << 1\n\ttake_int(nums.first())\n}\n',
200 'cannot use `string` as argument 1 to `take_int`; expected `int`')
201 fixed_dynamic_out := run_good(v3_bin, 'fixed_array_dynamic_receiver_method_before_builtin',
202 'fn (a []int) pointers() int {\n\treturn 41\n}\n\nfn main() {\n\tfixed := [3]int{}\n\tprintln(int_str(fixed.pointers()))\n}\n')
203 assert fixed_dynamic_out == '41'
204 nested_fixed_dynamic_out := run_good(v3_bin, 'nested_fixed_array_dynamic_receiver_method',
205 'fn (a [][2]int) pointers() int {\n\treturn 82\n}\n\nfn main() {\n\tfixed := [3][2]int{}\n\tprintln(int_str(fixed.pointers()))\n}\n')
206 assert nested_fixed_dynamic_out == '82'
207 fixed_alias_shape_out := run_good(v3_bin, 'fixed_array_builtin_not_alias_method',
208 'type F = [2]int\n\nfn (f F) pointers() int {\n\treturn 66\n}\n\nfn main() {\n\tmut fixed := [2]int{}\n\tptrs := unsafe { fixed.pointers() }\n\tprintln(int_str(ptrs.len))\n}\n')
209 assert fixed_alias_shape_out == '2'
210 plain_array_contains_out := run_good(v3_bin, 'plain_array_contains_not_alias_method',
211 'type A = []int\n\nfn (a A) contains(x int) int {\n\treturn 0\n}\n\nfn main() {\n\tnums := [1, 2, 3]\n\tif nums.contains(2) {\n\t\tprintln("builtin")\n\t} else {\n\t\tprintln("alias")\n\t}\n\talias := A(nums)\n\tprintln(int_str(alias.contains(2)))\n}\n')
212 assert plain_array_contains_out == 'builtin\n0'
213 module_primitive_out := run_good_project(v3_bin, 'module_primitive_array_receiver_method', {
214 'main.v': 'module main\n\nimport thing\n\nfn main() {\n\tprintln(thing.run())\n}\n'
215 'thing/mod.v': 'module thing\n\nfn (a []int) pointers() int {\n\treturn 64\n}\n\npub fn run() string {\n\tmut nums := []int{}\n\tnums << 1\n\treturn int_str(nums.pointers())\n}\n'
216 }, 'main.v')
217 assert module_primitive_out == '64'
218 fixed_out := run_good(v3_bin, 'fixed_array_pointers_original_storage',
219 'fn main() {\n\tmut fixed := [3]int{}\n\tfixed[0] = 1\n\tptrs := unsafe { fixed.pointers() }\n\tunsafe {\n\t\tp0 := &int(ptrs[0])\n\t\t*p0 = 9\n\t}\n\tprintln(int_str(fixed[0]))\n}\n')
220 assert fixed_out == '9'
221 fixed_expr_out := run_good(v3_bin, 'fixed_array_pointers_evaluates_receiver_once',
222 '__global calls int\n\nfn next() int {\n\tcalls = calls + 1\n\treturn 0\n}\n\nfn main() {\n\tmut rows := [1][2]int{}\n\trows[0][0] = 5\n\tptrs := unsafe { rows[next()].pointers() }\n\tunsafe {\n\t\tp0 := &int(ptrs[0])\n\t\t*p0 = 8\n\t}\n\tprintln(int_str(calls))\n\tprintln(int_str(rows[0][0]))\n}\n')
223 assert fixed_expr_out == '1\n8'
224 run_bad(v3_bin, 'fixed_array_pointers_rejects_rvalue_receiver',
225 'fn make_fixed() [2]int {\n\treturn [7, 8]!\n}\n\nfn main() {\n\t_ := unsafe { make_fixed().pointers() }\n}\n',
226 'fixed array receiver for `pointers` must be addressable')
227 run_bad(v3_bin, 'fixed_array_pointers_rejects_map_index_receiver',
228 'fn main() {\n\tmut m := map[string][2]int{}\n\tm["x"] = [1, 2]!\n\t_ := unsafe { m["x"].pointers() }\n}\n',
229 'fixed array receiver for `pointers` must be addressable')
230 fixed_len_expr_out := run_good(v3_bin, 'fixed_array_pointers_folds_len_expr',
231 'const segs = 2\n\nfn main() {\n\tmut const_len := [segs + 1]int{}\n\tconst_ptrs := unsafe { const_len.pointers() }\n\tmut shift_len := [8 >>> 1]int{}\n\tshift_ptrs := unsafe { shift_len.pointers() }\n\tprintln(int_str(const_ptrs.len))\n\tprintln(int_str(shift_ptrs.len))\n}\n')
232 assert fixed_len_expr_out == '3\n4'
233 run_bad(v3_bin, 'fixed_array_pointers_rejects_extra_arg',
234 'fn extra_arg() int {\n\treturn 1\n}\n\nfn main() {\n\tmut fixed := [3]int{}\n\t_ := unsafe { fixed.pointers(extra_arg()) }\n}\n',
235 'argument count mismatch for `fixed.pointers`: expected 1, got 2')
236}
237
238fn test_map_builtin_method_fallback_checks_arguments() {
239 v3_bin := build_v3()
240 run_bad(v3_bin, 'map_keys_rejects_extra_arg',
241 'fn extra_arg() int {\n\treturn 1\n}\n\nfn main() {\n\tmut m := map[string]int{}\n\t_ := m.keys(extra_arg())\n}\n',
242 'argument count mismatch for `m.keys`: expected 0, got 1')
243 run_bad(v3_bin, 'map_delete_rejects_bad_key_type',
244 'fn main() {\n\tmut m := map[string]int{}\n\tm.delete(123)\n}\n',
245 'cannot use `int` as argument 2 to `m.delete`; expected `string`')
246 run_bad(v3_bin, 'map_reserve_rejects_bad_count_type',
247 'fn main() {\n\tmut m := map[string]int{}\n\tm.reserve("bad")\n}\n',
248 'cannot use `string` as argument 2 to `m.reserve`; expected `u32`')
249 out := run_good(v3_bin, 'map_builtin_method_fallback',
250 'fn main() {\n\tmut m := map[string]int{}\n\tm["abc"] = 42\n\tmut moved := m.move()\n\tprintln(int_str(m.len))\n\tmoved.clear()\n\tmoved.reserve(6)\n\tmoved.delete("x")\n\tkeys := moved.keys()\n\tvalues := moved.values()\n\tcloned := moved.clone()\n\tprintln(int_str(keys.len + values.len + cloned.len))\n}\n')
251 assert out == '0\n0'
252 pointer_out := run_good(v3_bin, 'map_move_pointer_receiver_returns_map',
253 'fn take(m map[string]int) int {\n\treturn m.len\n}\n\nfn main() {\n\tmut m := map[string]int{}\n\tm["abc"] = 42\n\tp := &m\n\tprintln(int_str(take(p.move())))\n\tprintln(int_str(m.len))\n}\n')
254 assert pointer_out == '1\n0'
255 exact_out := run_good(v3_bin, 'exact_map_receiver_method_before_builtin',
256 'fn (m map[string]int) keys() int {\n\treturn 77\n}\n\nfn main() {\n\tmut m := map[string]int{}\n\tm["x"] = 1\n\tn := m.keys()\n\tprintln(int_str(n))\n}\n')
257 assert exact_out == '77'
258 alias_rvalue_out := run_good(v3_bin, 'map_alias_rvalue_receiver_method_before_builtin',
259 'type M = map[string]int\n\nfn (m M) delete(k string) int {\n\treturn 66\n}\n\nfn make_m() M {\n\tmut m := M(map[string]int{})\n\tm["x"] = 1\n\treturn m\n}\n\nfn main() {\n\tprintln(int_str(make_m().delete("x")))\n}\n')
260 assert alias_rvalue_out == '66'
261 plain_map_out := run_good(v3_bin, 'plain_map_builtin_not_alias_method',
262 'type M = map[string]int\n\nfn (m M) keys() int {\n\treturn 66\n}\n\nfn main() {\n\tmut m := map[string]int{}\n\tm["x"] = 1\n\tkeys := m.keys()\n\tprintln(int_str(keys.len))\n}\n')
263 assert plain_map_out == '1'
264 module_map_runtime_prefix_out := run_good_project(v3_bin,
265 'map_runtime_prefix_module_receiver_method', {
266 'main.v': 'module main\n\nimport map__utils\n\nfn main() {\n\tprintln(map__utils.run())\n}\n'
267 'map__utils/mod.v': 'module map__utils\n\nfn (m map[string]int) keys() int {\n\treturn 84\n}\n\npub fn run() string {\n\tmut m := map[string]int{}\n\tm["x"] = 1\n\treturn int_str(m.keys())\n}\n'
268 }, 'main.v')
269 assert module_map_runtime_prefix_out == '84'
270 module_map_out := run_good_project(v3_bin, 'map_module_receiver_method', {
271 'main.v': 'module main\n\nimport map\n\nfn main() {\n\tprintln(map.run())\n}\n'
272 'map/mod.v': 'module map\n\nfn (m map[string]int) keys() int {\n\treturn 85\n}\n\npub fn run() string {\n\tmut m := map[string]int{}\n\tm["x"] = 1\n\treturn int_str(m.keys())\n}\n'
273 }, 'main.v')
274 assert module_map_out == '85'
275 fixed_key_out := run_good(v3_bin, 'fixed_array_key_map_receiver_method_before_builtin',
276 'fn (m map[[2]string]int) keys() int {\n\treturn 88\n}\n\nfn main() {\n\tmut m := map[[2]string]int{}\n\tkey := ["a", "b"]!\n\tm[key] = 1\n\tprintln(int_str(m.keys()))\n}\n')
277 assert fixed_key_out == '88'
278 nested_fixed_key_out := run_good(v3_bin, 'nested_fixed_array_key_map_receiver_method',
279 'fn (m map[[3][2]int]int) keys() int {\n\treturn 99\n}\n\nfn main() {\n\tmut m := map[[3][2]int]int{}\n\tkey := [3][2]int{}\n\tm[key] = 1\n\tprintln(int_str(m.keys()))\n}\n')
280 assert nested_fixed_key_out == '99'
281 module_collection_out := run_good_project(v3_bin, 'module_collection_receiver_methods', {
282 'main.v': 'module main\n\nimport thing\n\nfn main() {\n\tprintln(thing.run())\n}\n'
283 'thing/mod.v': 'module thing\n\nstruct Foo {}\nstruct Key {}\n\nfn (m map[string]Foo) keys() int {\n\treturn 31\n}\n\nfn (a []Foo) pointers() int {\n\treturn 42\n}\n\nfn (m map[Key]int) keys() int {\n\treturn 53\n}\n\npub fn run() string {\n\tmut m := map[string]Foo{}\n\tm["x"] = Foo{}\n\titems := [Foo{}]\n\tkeyed := map[Key]int{}\n\treturn int_str(m.keys()) + "\\n" + int_str(items.pointers()) + "\\n" + int_str(keyed.keys())\n}\n'
284 }, 'main.v')
285 assert module_collection_out == '31\n42\n53'
286}
287
288fn test_runtime_inits_run_before_module_init() {
289 v3_bin := build_v3()
290 out := run_good_project(v3_bin, 'runtime_inits_before_module_init', {
291 'main.v': 'module main\n\nimport moda\n\nfn main() {\n\tprintln(int_str(moda.const_seen()))\n\tprintln(int_str(moda.global_seen()))\n}\n'
292 'moda/moda.v': "module moda\n\nconst const_map = map[string]int{\n\t'const': 5\n}\n\n__global (\n\tglobal_map = map[string]int{\n\t\t'global': 7\n\t}\n\tseen_const int\n\tseen_global int\n)\n\nfn init() {\n\tseen_const = const_map['const']\n\tseen_global = global_map['global']\n}\n\npub fn const_seen() int {\n\treturn seen_const\n}\n\npub fn global_seen() int {\n\treturn seen_global\n}\n"
293 }, 'main.v')
294 assert out == '5\n7'
295}
296
297fn test_string_index_type_is_u8() {
298 v3_bin := build_v3()
299 out := run_good(v3_bin, 'string_index_type_is_u8',
300 "fn main() {\n\ts := 'ABC'\n\tprintln(typeof(s[0]).name)\n\tprintln('\${s[2]}')\n}\n")
301 assert out == 'u8\n67'
302}
303
304fn test_f32_map_and_fixed_array_stringification() {
305 v3_bin := build_v3()
306 out := run_good(v3_bin, 'f32_map_stringification',
307 "fn main() {\n\tm := {\n\t\t'a': f32(1.5)\n\t}\n\tprintln(m)\n\tfixed := [f32(1.5), f32(2.25)]!\n\tmf := {\n\t\t'x': fixed\n\t}\n\tprintln(mf)\n}\n")
308 assert out == "{'a': 1.5}\n{'x': [1.5, 2.25]}"
309}
310
311fn test_u8_map_stringification_is_numeric() {
312 v3_bin := build_v3()
313 out := run_good(v3_bin, 'u8_map_stringification',
314 "fn main() {\n\tkeys := {\n\t\tu8(23): 'x'\n\t}\n\tvals := {\n\t\t'x': u8(23)\n\t}\n\tboth := {\n\t\tu8(65): u8(10)\n\t}\n\tprintln(keys)\n\tprintln(vals)\n\tprintln(both)\n}\n")
315 assert out == "{23: 'x'}\n{'x': 23}\n{65: 10}"
316}
317
318fn test_map_equality_uses_semantic_value_comparison() {
319 v3_bin := build_v3()
320 out := run_good(v3_bin, 'map_semantic_value_equality',
321 "struct Item {\n\tname string\n\tparts []string\n}\n\nfn join(a string, b string) string {\n\treturn a + b\n}\n\nfn main() {\n\tleft := {\n\t\t'x': Item{\n\t\t\tname: 'hello'.clone()\n\t\t\tparts: ['ab'.clone()]\n\t\t}\n\t}\n\tright := {\n\t\t'x': Item{\n\t\t\tname: join('he', 'llo')\n\t\t\tparts: [join('a', 'b')]\n\t\t}\n\t}\n\tarr_left := {\n\t\t'y': ['cd'.clone()]\n\t}\n\tarr_right := {\n\t\t'y': [join('c', 'd')]\n\t}\n\tprintln(left == right)\n\tprintln(left != right)\n\tprintln(arr_left == arr_right)\n}\n")
322 assert out == 'true\nfalse\ntrue'
323}
324
325fn test_array_equality_marks_struct_operator_used() {
326 v3_bin := build_v3()
327 out := run_good(v3_bin, 'array_eq_struct_operator_used',
328 'struct Item {\n\tvalue int\n}\n\nfn (a Item) == (b Item) bool {\n\treturn a.value % 10 == b.value % 10\n}\n\nfn main() {\n\tleft := [Item{value: 12}]\n\tright := [Item{value: 2}]\n\tprintln(left == right)\n}\n')
329 assert out == 'true'
330}
331
332fn test_zero_padded_interpolation_preserves_wide_integers() {
333 v3_bin := build_v3()
334 out := run_good(v3_bin, 'wide_zero_padded_interpolation',
335 "fn main() {\n\tbig := i64(5000000000)\n\tubig := u64(18446744073709551615)\n\tsmall := u64(42)\n\tprintln('\${big:012d}')\n\tprintln('\${ubig:020d}')\n\tprintln('\${small:08d}')\n}\n")
336 assert out == '005000000000\n18446744073709551615\n00000042'
337}
338
339fn test_formatted_interpolation_rune_and_long_float() {
340 v3_bin := build_v3()
341 out := run_good(v3_bin, 'formatted_interpolation_rune_and_long_float',
342 "fn main() {\n\tr := '\${rune(0x20ac):c}'\n\tprintln(int_str(r.len))\n\tprintln(int_str(int(r[0])) + ',' + int_str(int(r[1])) + ',' + int_str(int(r[2])))\n\tlong := '\${1.0:.200f}'\n\tprintln(int_str(long.len))\n\tprintln(int_str(int(long[0])) + ',' + int_str(int(long[1])) + ',' + int_str(int(long[2])) + ',' + int_str(int(long[long.len - 1])))\n}\n")
343 assert out == '3\n226,130,172\n202\n49,46,48,48'
344}
345