v2 / vlib / v / pref / pref_test.v
627 lines · 546 sloc · 21.69 KB · 63a85c16c9b5095a8683f8c22b6472a57edb5d7f
Raw
1import v.pref
2import v.vmod
3import os
4
5const vexe = @VEXE
6const vroot = os.dir(vexe)
7
8fn test_check_parametes() {
9 // reproducing issue https://github.com/vlang/v/issues/13983
10 _, cmd := pref.parse_args_and_show_errors(['help'], [''], true)
11 // no command found from args
12 assert cmd == ''
13}
14
15fn test_version_flag() {
16 v_ver := vmod.from_file(os.join_path(vroot, 'v.mod'))!.version
17 v_ver_cmd_res := os.execute_opt('${vexe} --version')!.output
18 assert v_ver_cmd_res.starts_with('V ${v_ver}'), v_ver_cmd_res
19
20 v_retry_ver_cmd_res := os.execute_opt('${vexe} retry --version')!.output
21 assert v_retry_ver_cmd_res != v_ver_cmd_res
22
23 v_git_ver_subcmd_res := os.execute_opt('${vexe} retry -- git --version')!.output
24 assert v_git_ver_subcmd_res !in [v_ver_cmd_res, v_retry_ver_cmd_res]
25
26 // Test version / verbosity toggle.
27 assert os.execute_opt('${vexe} -v')!.output == v_ver_cmd_res
28 assert os.execute_opt('${vexe} -cc tcc -v')!.output == v_ver_cmd_res
29
30 example_path := os.join_path(vroot, 'examples', 'hello_world.v')
31 v_verbose_cmd_res := os.execute_opt('${vexe} -v run ${example_path}')!.output
32 assert v_verbose_cmd_res != v_ver_cmd_res
33 assert v_verbose_cmd_res.contains('v.pref.lookup_path:')
34
35 v_verbose_cmd_with_additional_args_res := os.execute_opt('${vexe} -g -v run ${example_path}')!.output
36 assert v_verbose_cmd_with_additional_args_res != v_ver_cmd_res
37 assert v_verbose_cmd_with_additional_args_res.contains('v.pref.lookup_path:')
38}
39
40fn test_cross_compile_keeps_explicit_cc() {
41 target_os := if pref.get_host_os() == .linux { 'macos' } else { 'linux' }
42 custom_cc := 'cosmocc'
43
44 first, _ := pref.parse_args_and_show_errors(['help'], ['', '-cc', custom_cc, '-os', target_os],
45 false)
46 assert first.ccompiler_set_by_flag
47 assert first.ccompiler == custom_cc
48
49 second, _ := pref.parse_args_and_show_errors(['help'],
50 ['', '-os', target_os, '-cc', custom_cc], false)
51 assert second.ccompiler_set_by_flag
52 assert second.ccompiler == custom_cc
53}
54
55fn test_mac_is_alias_for_macos() {
56 os_kind := pref.os_from_string('mac') or {
57 assert false, err.msg()
58 return
59 }
60 assert os_kind == .macos
61 assert pref.OS.macos.is_target_of('mac')
62 assert !pref.OS.linux.is_target_of('mac')
63}
64
65fn test_bsd_target_matches_macos_and_bsd_systems() {
66 for os_kind in [pref.OS.macos, .freebsd, .openbsd, .netbsd, .dragonfly] {
67 assert os_kind.is_target_of('bsd')
68 }
69 assert !pref.OS.linux.is_target_of('bsd')
70 assert !pref.OS.windows.is_target_of('bsd')
71}
72
73fn test_disable_explicit_mutability_flag() {
74 target := os.join_path(vroot, 'examples', 'hello_world.v')
75 prefs, _ := pref.parse_args_and_show_errors([], ['-disable-explicit-mutability', target], false)
76 assert prefs.disable_explicit_mutability
77 assert prefs.build_options.contains('-disable-explicit-mutability')
78
79 prefs2, _ := pref.parse_args_and_show_errors([], ['--disable-explicit-mutability', target],
80 false)
81 assert prefs2.disable_explicit_mutability
82 assert prefs2.build_options.contains('--disable-explicit-mutability')
83}
84
85fn test_profile_flag_does_not_consume_direct_compile_target() {
86 target := os.join_path(vroot, 'examples', 'hello_world.v')
87 prefs, command := pref.parse_args_and_show_errors([], ['-profile', target], false)
88 assert command == target
89 assert prefs.path == target
90 assert prefs.is_prof
91 assert prefs.profile_file == '-'
92}
93
94fn test_profile_flag_does_not_consume_run_command() {
95 target := os.join_path(vroot, 'examples', 'hello_world.v')
96 prefs, command := pref.parse_args_and_show_errors([], ['-profile', 'run', target], false)
97 assert command == 'run'
98 assert prefs.path == target
99 assert prefs.is_run
100 assert prefs.is_prof
101 assert prefs.profile_file == '-'
102}
103
104fn test_profile_flag_still_accepts_explicit_output_file() {
105 target := os.join_path(vroot, 'examples', 'hello_world.v')
106 prefs, command := pref.parse_args_and_show_errors([], ['-profile', 'profile.txt', target],
107 false)
108 assert command == target
109 assert prefs.path == target
110 assert prefs.is_prof
111 assert prefs.profile_file == 'profile.txt'
112}
113
114fn new_wasm_preferences() pref.Preferences {
115 return pref.Preferences{
116 backend: .wasm
117 os: .browser
118 arch: .wasm32
119 }
120}
121
122fn new_c_preferences() pref.Preferences {
123 return pref.Preferences{
124 backend: .c
125 os: .linux
126 arch: .amd64
127 }
128}
129
130fn test_c_backend_filters_backend_specific_files() {
131 prefs := new_c_preferences()
132 dir := os.join_path(os.vtmp_dir(), 'c_backend_filters')
133 filtered := prefs.should_compile_filtered_files(dir, [
134 'mod.c.v',
135 'mod.js.v',
136 'mod.v',
137 'mod.wasm.v',
138 ])
139 assert filtered == [
140 os.join_path(dir, 'mod.c.v'),
141 os.join_path(dir, 'mod.v'),
142 ]
143}
144
145fn test_c_backend_skips_modules_with_only_non_c_variants() {
146 prefs := new_c_preferences()
147 filtered := prefs.should_compile_filtered_files('sus', ['sus.js.v', 'sus.wasm.v'])
148 assert filtered.len == 0
149}
150
151fn test_wasm_backend_filters_backend_specific_files() {
152 prefs := new_wasm_preferences()
153 dir := os.join_path(os.vtmp_dir(), 'wasm_backend_filters')
154 filtered := prefs.should_compile_filtered_files(dir, [
155 'mod.c.v',
156 'mod.js.v',
157 'mod.v',
158 'mod.wasm.v',
159 ])
160 assert filtered == [
161 os.join_path(dir, 'mod.v'),
162 os.join_path(dir, 'mod.wasm.v'),
163 ]
164}
165
166fn test_wasm_backend_skips_modules_with_only_c_and_js_variants() {
167 prefs := new_wasm_preferences()
168 filtered := prefs.should_compile_filtered_files('sus', ['sus.c.v', 'sus.js.v'])
169 assert filtered.len == 0
170}
171
172fn filtered_file_names_for_os(os_kind pref.OS, files []string) []string {
173 prefs := pref.Preferences{
174 os: os_kind
175 }
176 dir := os.join_path(os.vtmp_dir(), 'environment_specific_files')
177 mut res := []string{}
178 for file in prefs.should_compile_filtered_files(dir, files) {
179 res << os.base(file)
180 }
181 return res
182}
183
184fn test_bsd_specific_files_are_filtered_by_target_os() {
185 for os_kind in [pref.OS.macos, .freebsd, .openbsd, .netbsd, .dragonfly] {
186 assert filtered_file_names_for_os(os_kind, ['mod_bsd.c.v', 'mod_bsd.v']) == [
187 'mod_bsd.c.v',
188 'mod_bsd.v',
189 ]
190 }
191 assert filtered_file_names_for_os(.linux, ['mod_bsd.c.v', 'mod_bsd.v']).len == 0
192 assert filtered_file_names_for_os(.windows, ['mod_bsd.c.v', 'mod_bsd.v']).len == 0
193}
194
195fn test_bsd_specific_files_prefer_more_specific_variants() {
196 mut files := [
197 'main.v',
198 'something_default.c.v',
199 'something_windows.c.v',
200 ]
201 assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_default.c.v']
202
203 files << 'something_nix.c.v'
204 assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_nix.c.v']
205
206 files << 'something_bsd.c.v'
207 assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_bsd.c.v']
208
209 files << 'something_freebsd.c.v'
210 assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_freebsd.c.v']
211}
212
213fn test_bsd_specific_files_prefer_darwin_on_macos() {
214 files := [
215 'main.v',
216 'something_nix.c.v',
217 'something_bsd.v',
218 'something_darwin.v',
219 ]
220 assert filtered_file_names_for_os(.macos, files) == ['main.v', 'something_darwin.v']
221}
222
223fn test_explicit_gc_mode_is_forwarded_to_build_module() {
224 target := os.join_path(vroot, 'examples', 'hello_world.v')
225 for gc_mode in ['none', 'boehm', 'boehm_full', 'boehm_incr', 'boehm_full_opt', 'boehm_incr_opt',
226 'boehm_leak'] {
227 prefs, _ := pref.parse_args_and_show_errors([], ['-usecache', '-gc', gc_mode, target],
228 false)
229 assert prefs.build_options.contains('-gc ${gc_mode}')
230 }
231}
232
233fn test_cross_compile_defaults_windows_to_the_cross_compiler_arch() {
234 if pref.get_host_os() == .windows {
235 return
236 }
237 target := os.join_path(vroot, 'examples', 'hello_world.v')
238 prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'windows', target], false)
239 assert prefs.arch == .amd64
240 assert prefs.ccompiler == 'x86_64-w64-mingw32-gcc'
241}
242
243fn test_cross_compile_windows_m32_uses_i386_arch_and_compiler() {
244 if pref.get_host_os() == .windows {
245 return
246 }
247 target := os.join_path(vroot, 'examples', 'hello_world.v')
248 prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'windows', '-m32', target], false)
249 assert !prefs.m64
250 assert prefs.arch == .i386
251 assert prefs.ccompiler == 'i686-w64-mingw32-gcc'
252 assert prefs.build_options.contains('-m32')
253}
254
255fn test_cross_compile_defaults_linux_to_amd64() {
256 if pref.get_host_os() == .linux {
257 return
258 }
259 target := os.join_path(vroot, 'examples', 'hello_world.v')
260 prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'linux', target], false)
261 assert prefs.arch == .amd64
262 assert prefs.ccompiler == 'clang'
263}
264
265fn test_cross_compile_infers_android_arch_from_vcross_compiler_name() {
266 target := os.join_path(vroot, 'examples', 'hello_world.v')
267 old_cross_compiler := os.getenv('VCROSS_COMPILER_NAME')
268 defer {
269 os.setenv('VCROSS_COMPILER_NAME', old_cross_compiler, true)
270 }
271 for compiler_name, expected_arch in {
272 'aarch64-linux-android21-clang': pref.Arch.arm64
273 'armv7a-linux-androideabi21-clang': pref.Arch.arm32
274 'i686-linux-android21-clang': pref.Arch.i386
275 'x86_64-linux-android21-clang': pref.Arch.amd64
276 } {
277 os.setenv('VCROSS_COMPILER_NAME', compiler_name, true)
278 prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'android', target], false)
279 assert prefs.arch == expected_arch
280 assert prefs.ccompiler == compiler_name
281 }
282}
283
284fn test_musl_defaults_to_no_gc() {
285 target := os.join_path(vroot, 'examples', 'hello_world.v')
286 prefs, _ := pref.parse_args_and_show_errors([], ['', '-musl', target], false)
287 assert prefs.is_musl
288 assert prefs.gc_mode == .no_gc
289}
290
291fn test_musl_keeps_explicit_gc_selection() {
292 target := os.join_path(vroot, 'examples', 'hello_world.v')
293 prefs, _ := pref.parse_args_and_show_errors([], ['', '-musl', '-gc', 'boehm', target], false)
294 assert prefs.is_musl
295 assert prefs.gc_mode == .boehm_full_opt
296}
297
298fn test_prealloc_defaults_to_no_gc() {
299 target := os.join_path(vroot, 'examples', 'hello_world.v')
300 prefs, _ := pref.parse_args_and_show_errors([], ['', '-prealloc', target], false)
301 assert prefs.prealloc
302 assert prefs.gc_mode == .no_gc
303}
304
305fn test_prealloc_overrides_explicit_gc_selection() {
306 target := os.join_path(vroot, 'examples', 'hello_world.v')
307 prefs, _ := pref.parse_args_and_show_errors([], ['', '-gc', 'boehm', '-prealloc', target],
308 false)
309 assert prefs.prealloc
310 assert prefs.gc_mode == .no_gc
311 assert 'gcboehm' !in prefs.compile_defines
312 assert prefs.build_options.join(' ').contains('-gc none')
313}
314
315fn stale_windows_gc_prefs(gc_set_by_flag bool) pref.Preferences {
316 mut prefs := pref.Preferences{
317 os: .windows
318 ccompiler_type: .msvc
319 gc_mode: .boehm_full_opt
320 gc_set_by_flag: gc_set_by_flag
321 compile_defines: ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom']
322 compile_defines_all: ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom']
323 compile_values: map[string]string{}
324 build_options: ['-prod', '-d gcboehm', '-d gcboehm_full', '-d gcboehm_opt']
325 }
326 prefs.compile_values['gcboehm'] = 'true'
327 prefs.compile_values['gcboehm_full'] = 'true'
328 prefs.compile_values['gcboehm_opt'] = 'true'
329 prefs.compile_values['custom'] = 'true'
330 return prefs
331}
332
333fn test_windows_msvc_gc_defaults_are_cleared_after_compiler_resolution() {
334 mut prefs := stale_windows_gc_prefs(false)
335
336 prefs.normalize_gc_defaults_for_resolved_ccompiler()
337
338 assert prefs.gc_mode == .no_gc
339 assert prefs.build_options == ['-prod', '-gc', 'none']
340 assert prefs.compile_defines == ['custom']
341 assert prefs.compile_defines_all == ['custom']
342 assert prefs.compile_values == {
343 'custom': 'true'
344 }
345}
346
347fn test_windows_msvc_gc_defaults_keep_explicit_gc_selection() {
348 mut prefs := stale_windows_gc_prefs(true)
349 prefs.build_options = ['-prod', '-gc', 'boehm', '-d gcboehm', '-d gcboehm_full', '-d gcboehm_opt']
350
351 prefs.normalize_gc_defaults_for_resolved_ccompiler()
352
353 assert prefs.gc_mode == .boehm_full_opt
354 assert prefs.build_options == ['-prod', '-gc', 'boehm', '-d gcboehm', '-d gcboehm_full',
355 '-d gcboehm_opt']
356 assert prefs.compile_defines == ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom']
357 assert prefs.compile_defines_all == ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom']
358 assert prefs.compile_values == {
359 'custom': 'true'
360 'gcboehm': 'true'
361 'gcboehm_full': 'true'
362 'gcboehm_opt': 'true'
363 }
364}
365
366fn test_m32_sets_i386_arch_when_not_explicitly_set() {
367 target := os.join_path(vroot, 'examples', 'hello_world.v')
368 prefs, _ := pref.parse_args_and_show_errors([], ['', '-m32', target], false)
369 assert !prefs.m64
370 assert prefs.arch == .i386
371 assert prefs.build_options.contains('-m32')
372}
373
374fn test_m32_does_not_override_explicit_arch() {
375 target := os.join_path(vroot, 'examples', 'hello_world.v')
376 prefs, _ := pref.parse_args_and_show_errors([], ['', '-arch', 'amd64', '-m32', target], false)
377 assert !prefs.m64
378 assert prefs.arch == .amd64
379 assert prefs.build_options.contains('-m32')
380}
381
382fn test_v_cmds_and_flags() {
383 build_cmd_res := os.execute('${vexe} build ${vroot}/examples/hello_world.v')
384 assert build_cmd_res.output.trim_space() == 'Use `v ${vroot}/examples/hello_world.v` instead.'
385
386 too_many_targets_res :=
387 os.execute('${vexe} ${vroot}/examples/hello_world.v ${vroot}/examples/fizz_buzz.v')
388 assert too_many_targets_res.output.trim_space() == 'Too many targets. Specify just one target: <target.v|target_directory>.'
389
390 unknown_arg_res := os.execute('${vexe} -xyz')
391 assert unknown_arg_res.output.trim_space() == 'Unknown argument `-xyz`'
392
393 unknown_arg_for_cmd_res := os.execute('${vexe} build-module -xyz ${vroot}/vlib/math')
394 assert unknown_arg_for_cmd_res.output.trim_space() == 'Unknown argument `-xyz` for command `build-module`'
395
396 eval_removed_message := 'use v -v2 -eval file.v'
397 eval_flag_res := os.execute('${vexe} -eval ${vroot}/examples/hello_world.v')
398 assert eval_flag_res.exit_code == 1
399 assert eval_flag_res.output.trim_space() == eval_removed_message
400
401 eval_backend_res := os.execute('${vexe} -backend eval ${vroot}/examples/hello_world.v')
402 assert eval_backend_res.exit_code == 1
403 assert eval_backend_res.output.trim_space() == eval_removed_message
404
405 interpret_flag_res := os.execute('${vexe} -interpret ${vroot}/examples/hello_world.v')
406 assert interpret_flag_res.exit_code == 1
407 assert interpret_flag_res.output.trim_space() == eval_removed_message
408
409 interpret_command_res := os.execute('${vexe} interpret ${vroot}/examples/hello_world.v')
410 assert interpret_command_res.exit_code == 1
411 assert interpret_command_res.output.trim_space() == eval_removed_message
412
413 no_run_files_res := os.execute('${vexe} run')
414 assert no_run_files_res.output.trim_space() == 'v run: no v files listed'
415
416 no_bm_files_res := os.execute('${vexe} build-module')
417 assert no_bm_files_res.output.trim_space() == 'v build-module: no module specified'
418}
419
420fn test_build_command_compiles_vsh_without_running_it() {
421 test_dir := os.join_path(os.vtmp_dir(), 'v_pref_build_vsh_${os.getpid()}')
422 os.rmdir_all(test_dir) or {}
423 os.mkdir_all(test_dir)!
424 defer {
425 os.rmdir_all(test_dir) or {}
426 }
427 script_path := os.join_path(test_dir, 'build_only.vsh')
428 marker_path := os.join_path(test_dir, 'marker.txt')
429 mut exe_path := os.join_path(test_dir, 'build_only')
430 $if windows {
431 exe_path += '.exe'
432 }
433 os.write_file(script_path, "import os
434
435fn main() {
436 marker_path := os.join_path(@DIR, 'marker.txt')
437 os.write_file(marker_path, 'ran') or { panic(err) }
438 println('ran')
439}
440")!
441 build_res := os.execute('${os.quoted_path(vexe)} -silent build ${os.quoted_path(script_path)}')
442 assert build_res.exit_code == 0, build_res.output
443 assert build_res.output == ''
444 assert !os.exists(marker_path)
445 assert os.is_file(exe_path)
446
447 run_res := os.execute(os.quoted_path(exe_path))
448 assert run_res.exit_code == 0, run_res.output
449 assert run_res.output.trim_space() == 'ran'
450 assert os.read_file(marker_path)! == 'ran'
451}
452
453const tfile = os.join_path(os.vtmp_dir(), 'unknown_options_output.c')
454
455fn test_unknown_option_flags_no_run() {
456 os.chdir(os.dir(@VEXE))!
457 os.rm(tfile) or {}
458
459 res1 :=
460 os.execute('${os.quoted_path(@VEXE)} -o ${os.quoted_path(tfile)} examples/hello_world.v --an-unknown-option')
461 assert res1.exit_code == 1, res1.output
462 assert res1.output.starts_with('Unknown argument')
463 assert res1.output.contains('--an-unknown-option')
464 assert !os.exists(tfile)
465
466 res2 :=
467 os.execute('${os.quoted_path(@VEXE)} -o ${os.quoted_path(tfile)} --an-unknown-option examples/hello_world.v')
468 assert res2.exit_code == 1, res2.output
469 assert res2.output.starts_with('Unknown argument')
470 assert res2.output.contains('--an-unknown-option')
471 assert !os.exists(tfile)
472}
473
474fn test_unknown_option_flags_with_run() {
475 res_run_o :=
476 os.execute('${os.quoted_path(@VEXE)} -o ${os.quoted_path(tfile)} run examples/hello_world.v --an-unknown-option')
477 assert res_run_o.exit_code == 0, res_run_o.output
478 assert res_run_o.output == '' // because of -o, there should not be an actual run, since compilation stopped after generating the .c file
479 assert os.exists(tfile)
480 os.rm(tfile) or {}
481
482 res_run_no_o_unknown_before_run :=
483 os.execute('${os.quoted_path(@VEXE)} --an-unknown-option run examples/hello_world.v ')
484 assert res_run_no_o_unknown_before_run.exit_code == 1, res_run_no_o_unknown_before_run.output
485 assert res_run_no_o_unknown_before_run.output.starts_with('Unknown argument')
486 assert res_run_no_o_unknown_before_run.output.contains('--an-unknown-option')
487 assert !os.exists(tfile)
488
489 res_run_no_o :=
490 os.execute('${os.quoted_path(@VEXE)} run examples/hello_world.v --an-unknown-option')
491 assert res_run_no_o.exit_code == 0, res_run_no_o.output
492 assert res_run_no_o.output.trim_space() == 'Hello, World!'
493 assert !os.exists(tfile)
494}
495
496fn test_missing_explicit_ccompiler_reports_error() {
497 target := os.join_path(vroot, 'examples', 'hello_world.v')
498 missing_cc := 'missing_compiler_17126_for_pref_test'
499 output := os.join_path(os.vtmp_dir(), 'missing_explicit_ccompiler_output')
500 mut expected_output := output
501 $if windows {
502 expected_output += '.exe'
503 }
504 os.rm(expected_output) or {}
505 res :=
506 os.execute('${os.quoted_path(@VEXE)} -cc ${missing_cc} -o ${os.quoted_path(output)} ${os.quoted_path(target)}')
507 assert res.exit_code != 0
508 assert res.output.contains(missing_cc), res.output
509 assert res.output.to_lower().contains('not found') || res.output.to_lower().contains('missing'), res.output
510
511 assert !os.exists(expected_output)
512}
513
514fn test_generate_c_project_flag_parsing() {
515 target := os.join_path(vroot, 'examples', 'hello_world.v')
516 prefs, _ := pref.parse_args_and_show_errors([], ['-generate-c-project', 'cproj', target], false)
517 assert prefs.generate_c_project == 'cproj'
518 assert prefs.use_cache == false
519}
520
521fn test_generate_c_project_creates_build_files() {
522 output_dir := os.join_path(os.vtmp_dir(), 'v_generate_c_project_json')
523 os.rmdir_all(output_dir) or {}
524 defer {
525 os.rmdir_all(output_dir) or {}
526 }
527 target := os.join_path(vroot, 'examples', 'json.v')
528 cmd := '${os.quoted_path(vexe)} -generate-c-project ${os.quoted_path(output_dir)} ${os.quoted_path(target)}'
529 res := os.execute(cmd)
530 assert res.exit_code == 0, res.output
531 for rel_path in ['json.c', 'build_command.txt', 'build.sh', 'build.bat', 'Makefile'] {
532 assert os.is_file(os.join_path(output_dir, rel_path))
533 }
534 build_command := os.read_file(os.join_path(output_dir, 'build_command.txt')) or { panic(err) }
535 generated_c_path := os.join_path(output_dir, 'json.c')
536 normalized_build_command := normalized_build_path(build_command)
537 assert normalized_build_command.contains(normalized_build_path(generated_c_path))
538 || normalized_build_command.contains(normalized_build_path(os.short_path(generated_c_path)))
539 assert build_command.contains('cJSON.c')
540 assert !build_command.contains('.tmp.c')
541 assert !build_command.contains('.module.')
542}
543
544fn normalized_build_path(path string) string {
545 mut normalized := path.replace('\\', '/')
546 for normalized.contains('//') {
547 normalized = normalized.replace('//', '/')
548 }
549 return normalized
550}
551
552fn test_output_flag_accepts_directory_path() {
553 output_dir := os.join_path(os.vtmp_dir(), 'v_output_flag_directory')
554 os.rmdir_all(output_dir) or {}
555 defer {
556 os.rmdir_all(output_dir) or {}
557 }
558 target := os.join_path(vroot, 'examples', 'hello_world.v')
559 output_arg := output_dir + os.path_separator
560 res :=
561 os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(output_arg)} ${os.quoted_path(target)}')
562 assert res.exit_code == 0, res.output
563 assert os.is_dir(output_dir)
564 mut expected_output := os.join_path(output_dir, 'hello_world')
565 $if windows {
566 expected_output += '.exe'
567 }
568 assert os.is_file(expected_output)
569}
570
571fn test_tcc_shared_builds_disable_backtraces() {
572 mut shared_prefs := &pref.Preferences{
573 path: 'libfoo.v'
574 is_shared: true
575 ccompiler: 'tinyc'
576 }
577 shared_prefs.fill_with_defaults()
578 assert 'no_backtrace' in shared_prefs.compile_defines_all
579
580 mut regular_prefs := &pref.Preferences{
581 path: 'main.v'
582 ccompiler: 'tinyc'
583 }
584 regular_prefs.fill_with_defaults()
585 assert 'no_backtrace' !in regular_prefs.compile_defines_all
586}
587
588fn test_late_resolved_tcc_shared_builds_disable_backtraces() {
589 mut shared_prefs := &pref.Preferences{
590 path: 'libfoo.v'
591 is_shared: true
592 ccompiler: 'gcc'
593 }
594 shared_prefs.fill_with_defaults()
595 assert 'no_backtrace' !in shared_prefs.compile_defines_all
596
597 shared_prefs.ccompiler_type = .tinyc
598 shared_prefs.normalize_gc_defaults_for_resolved_ccompiler()
599
600 assert 'no_backtrace' in shared_prefs.compile_defines_all
601 assert shared_prefs.build_options.contains('-d no_backtrace')
602}
603
604fn test_wayland_only_linux_session_surfaces_a_v_error_for_gg() {
605 if os.user_os() == 'windows' {
606 return
607 }
608 pid := os.getpid()
609 test_dir := os.join_path(os.vtmp_dir(), 'v_issue_18030_gg_wayland_${pid}')
610 source_path := os.join_path(test_dir, 'main.v')
611 exe_path := os.join_path(test_dir, 'app')
612 source := 'import gg as _\n\nfn main() {}\n'
613 os.mkdir_all(test_dir) or { panic(err) }
614 os.write_file(source_path, source) or { panic(err) }
615 defer {
616 os.rmdir_all(test_dir) or {}
617 }
618 cmd := 'DISPLAY= WAYLAND_DISPLAY=wayland-0 XDG_SESSION_TYPE=wayland ${os.quoted_path(vexe)} -os linux -o ${os.quoted_path(exe_path)} ${os.quoted_path(source_path)}'
619 res := os.execute(cmd)
620 output := res.output.replace('\r', '')
621 if res.exit_code == 0 {
622 eprintln('> failed command: ${cmd}')
623 }
624 assert res.exit_code != 0
625 assert output.contains('Wayland-only Linux session without `-d sokol_wayland`')
626 assert !output.contains('C error. This should never happen.')
627}
628