| 1 | import v.pref |
| 2 | import v.vmod |
| 3 | import os |
| 4 | |
| 5 | const vexe = @VEXE |
| 6 | const vroot = os.dir(vexe) |
| 7 | |
| 8 | fn 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 | |
| 15 | fn 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 | |
| 40 | fn 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 | |
| 55 | fn test_v2_only_flags_are_forwarded_by_v1_wrapper() { |
| 56 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 57 | prefs, command := pref.parse_args_and_show_errors(['help'], [ |
| 58 | '', |
| 59 | '-v2', |
| 60 | '-freestanding', |
| 61 | '-os', |
| 62 | 'none', |
| 63 | '--skip-builtin', |
| 64 | '--skip-type-check', |
| 65 | '--debug', |
| 66 | '--showcc', |
| 67 | '--stats', |
| 68 | '-print-parsed-files', |
| 69 | '--profile-alloc', |
| 70 | '--single-backend', |
| 71 | '-O0', |
| 72 | '-fhooks', |
| 73 | 'output,panic,alloc', |
| 74 | target, |
| 75 | ], false) |
| 76 | assert command == target |
| 77 | assert prefs.use_v2 |
| 78 | assert prefs.is_bare |
| 79 | assert prefs.build_options.contains('-os none') |
| 80 | assert prefs.build_options.contains('-fhooks output,panic,alloc') |
| 81 | } |
| 82 | |
| 83 | fn test_vexe_path_normalizes_relative_env_path() { |
| 84 | old_wd := os.getwd() |
| 85 | old_vexe := os.getenv_opt('VEXE') |
| 86 | test_root := os.join_path(os.vtmp_dir(), 'pref_vexe_path_relative_env_test') |
| 87 | os.rmdir_all(test_root) or {} |
| 88 | os.mkdir_all(test_root)! |
| 89 | fake_vexe := os.join_path(test_root, 'v') |
| 90 | os.write_file(fake_vexe, '')! |
| 91 | defer { |
| 92 | os.chdir(old_wd) or {} |
| 93 | if vexe_env := old_vexe { |
| 94 | os.setenv('VEXE', vexe_env, true) |
| 95 | } else { |
| 96 | os.unsetenv('VEXE') |
| 97 | } |
| 98 | os.rmdir_all(test_root) or {} |
| 99 | } |
| 100 | os.chdir(test_root)! |
| 101 | os.setenv('VEXE', './v', true) |
| 102 | expected_vexe := os.real_path(fake_vexe) |
| 103 | assert pref.vexe_path() == expected_vexe |
| 104 | assert os.getenv('VEXE') == expected_vexe |
| 105 | } |
| 106 | |
| 107 | fn test_mac_is_alias_for_macos() { |
| 108 | os_kind := pref.os_from_string('mac') or { |
| 109 | assert false, err.msg() |
| 110 | return |
| 111 | } |
| 112 | assert os_kind == .macos |
| 113 | assert pref.OS.macos.is_target_of('mac') |
| 114 | assert !pref.OS.linux.is_target_of('mac') |
| 115 | } |
| 116 | |
| 117 | fn test_bsd_target_matches_macos_and_bsd_systems() { |
| 118 | for os_kind in [pref.OS.macos, .freebsd, .openbsd, .netbsd, .dragonfly] { |
| 119 | assert os_kind.is_target_of('bsd') |
| 120 | } |
| 121 | assert !pref.OS.linux.is_target_of('bsd') |
| 122 | assert !pref.OS.windows.is_target_of('bsd') |
| 123 | } |
| 124 | |
| 125 | fn test_disable_explicit_mutability_flag() { |
| 126 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 127 | prefs, _ := pref.parse_args_and_show_errors([], ['-disable-explicit-mutability', target], false) |
| 128 | assert prefs.disable_explicit_mutability |
| 129 | assert prefs.build_options.contains('-disable-explicit-mutability') |
| 130 | |
| 131 | prefs2, _ := pref.parse_args_and_show_errors([], ['--disable-explicit-mutability', target], |
| 132 | false) |
| 133 | assert prefs2.disable_explicit_mutability |
| 134 | assert prefs2.build_options.contains('--disable-explicit-mutability') |
| 135 | } |
| 136 | |
| 137 | fn test_profile_flag_does_not_consume_direct_compile_target() { |
| 138 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 139 | prefs, command := pref.parse_args_and_show_errors([], ['-profile', target], false) |
| 140 | assert command == target |
| 141 | assert prefs.path == target |
| 142 | assert prefs.is_prof |
| 143 | assert prefs.profile_file == '-' |
| 144 | } |
| 145 | |
| 146 | fn test_profile_flag_does_not_consume_run_command() { |
| 147 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 148 | prefs, command := pref.parse_args_and_show_errors([], ['-profile', 'run', target], false) |
| 149 | assert command == 'run' |
| 150 | assert prefs.path == target |
| 151 | assert prefs.is_run |
| 152 | assert prefs.is_prof |
| 153 | assert prefs.profile_file == '-' |
| 154 | } |
| 155 | |
| 156 | fn test_profile_flag_still_accepts_explicit_output_file() { |
| 157 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 158 | prefs, command := pref.parse_args_and_show_errors([], ['-profile', 'profile.txt', target], |
| 159 | false) |
| 160 | assert command == target |
| 161 | assert prefs.path == target |
| 162 | assert prefs.is_prof |
| 163 | assert prefs.profile_file == 'profile.txt' |
| 164 | } |
| 165 | |
| 166 | fn new_wasm_preferences() pref.Preferences { |
| 167 | return pref.Preferences{ |
| 168 | backend: .wasm |
| 169 | os: .browser |
| 170 | arch: .wasm32 |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | fn new_c_preferences() pref.Preferences { |
| 175 | return pref.Preferences{ |
| 176 | backend: .c |
| 177 | os: .linux |
| 178 | arch: .amd64 |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | fn test_c_backend_filters_backend_specific_files() { |
| 183 | prefs := new_c_preferences() |
| 184 | dir := os.join_path(os.vtmp_dir(), 'c_backend_filters') |
| 185 | filtered := prefs.should_compile_filtered_files(dir, [ |
| 186 | 'mod.c.v', |
| 187 | 'mod.js.v', |
| 188 | 'mod.v', |
| 189 | 'mod.wasm.v', |
| 190 | ]) |
| 191 | assert filtered == [ |
| 192 | os.join_path(dir, 'mod.c.v'), |
| 193 | os.join_path(dir, 'mod.v'), |
| 194 | ] |
| 195 | } |
| 196 | |
| 197 | fn test_c_backend_skips_modules_with_only_non_c_variants() { |
| 198 | prefs := new_c_preferences() |
| 199 | filtered := prefs.should_compile_filtered_files('sus', ['sus.js.v', 'sus.wasm.v']) |
| 200 | assert filtered.len == 0 |
| 201 | } |
| 202 | |
| 203 | fn test_wasm_backend_filters_backend_specific_files() { |
| 204 | prefs := new_wasm_preferences() |
| 205 | dir := os.join_path(os.vtmp_dir(), 'wasm_backend_filters') |
| 206 | filtered := prefs.should_compile_filtered_files(dir, [ |
| 207 | 'mod.c.v', |
| 208 | 'mod.js.v', |
| 209 | 'mod.v', |
| 210 | 'mod.wasm.v', |
| 211 | ]) |
| 212 | assert filtered == [ |
| 213 | os.join_path(dir, 'mod.v'), |
| 214 | os.join_path(dir, 'mod.wasm.v'), |
| 215 | ] |
| 216 | } |
| 217 | |
| 218 | fn test_wasm_backend_skips_modules_with_only_c_and_js_variants() { |
| 219 | prefs := new_wasm_preferences() |
| 220 | filtered := prefs.should_compile_filtered_files('sus', ['sus.c.v', 'sus.js.v']) |
| 221 | assert filtered.len == 0 |
| 222 | } |
| 223 | |
| 224 | fn filtered_file_names_for_os(os_kind pref.OS, files []string) []string { |
| 225 | prefs := pref.Preferences{ |
| 226 | os: os_kind |
| 227 | } |
| 228 | dir := os.join_path(os.vtmp_dir(), 'environment_specific_files') |
| 229 | mut res := []string{} |
| 230 | for file in prefs.should_compile_filtered_files(dir, files) { |
| 231 | res << os.base(file) |
| 232 | } |
| 233 | return res |
| 234 | } |
| 235 | |
| 236 | fn test_bsd_specific_files_are_filtered_by_target_os() { |
| 237 | for os_kind in [pref.OS.macos, .freebsd, .openbsd, .netbsd, .dragonfly] { |
| 238 | assert filtered_file_names_for_os(os_kind, ['mod_bsd.c.v', 'mod_bsd.v']) == [ |
| 239 | 'mod_bsd.c.v', |
| 240 | 'mod_bsd.v', |
| 241 | ] |
| 242 | } |
| 243 | assert filtered_file_names_for_os(.linux, ['mod_bsd.c.v', 'mod_bsd.v']).len == 0 |
| 244 | assert filtered_file_names_for_os(.windows, ['mod_bsd.c.v', 'mod_bsd.v']).len == 0 |
| 245 | } |
| 246 | |
| 247 | fn test_bsd_specific_files_prefer_more_specific_variants() { |
| 248 | mut files := [ |
| 249 | 'main.v', |
| 250 | 'something_default.c.v', |
| 251 | 'something_windows.c.v', |
| 252 | ] |
| 253 | assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_default.c.v'] |
| 254 | |
| 255 | files << 'something_nix.c.v' |
| 256 | assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_nix.c.v'] |
| 257 | |
| 258 | files << 'something_bsd.c.v' |
| 259 | assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_bsd.c.v'] |
| 260 | |
| 261 | files << 'something_freebsd.c.v' |
| 262 | assert filtered_file_names_for_os(.freebsd, files) == ['main.v', 'something_freebsd.c.v'] |
| 263 | } |
| 264 | |
| 265 | fn test_bsd_specific_files_prefer_darwin_on_macos() { |
| 266 | files := [ |
| 267 | 'main.v', |
| 268 | 'something_nix.c.v', |
| 269 | 'something_bsd.v', |
| 270 | 'something_darwin.v', |
| 271 | ] |
| 272 | assert filtered_file_names_for_os(.macos, files) == ['main.v', 'something_darwin.v'] |
| 273 | } |
| 274 | |
| 275 | fn test_explicit_gc_mode_is_forwarded_to_build_module() { |
| 276 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 277 | for gc_mode in ['none', 'boehm', 'boehm_full', 'boehm_incr', 'boehm_full_opt', 'boehm_incr_opt', |
| 278 | 'boehm_leak'] { |
| 279 | prefs, _ := pref.parse_args_and_show_errors([], ['-usecache', '-gc', gc_mode, target], |
| 280 | false) |
| 281 | assert prefs.build_options.contains('-gc ${gc_mode}') |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | fn test_v_compiler_targets_default_to_no_gc() { |
| 286 | for target in [ |
| 287 | os.join_path(vroot, 'cmd', 'v'), |
| 288 | os.join_path(vroot, 'cmd', 'v') + os.path_separator, |
| 289 | os.join_path(vroot, 'cmd', 'v', 'v.v'), |
| 290 | os.join_path(vroot, 'cmd', 'v2'), |
| 291 | os.join_path(vroot, 'cmd', 'v2') + os.path_separator, |
| 292 | os.join_path(vroot, 'cmd', 'v2', 'v2.v'), |
| 293 | os.join_path(vroot, 'cmd', 'tools', 'vfmt.v'), |
| 294 | ] { |
| 295 | prefs, _ := pref.parse_args_and_show_errors([], ['', target], false) |
| 296 | assert prefs.gc_mode == .no_gc |
| 297 | assert prefs.build_options.join(' ').contains('-gc none') |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | fn test_v_compiler_targets_keep_explicit_gc_selection() { |
| 302 | target := os.join_path(vroot, 'cmd', 'v2', 'v2.v') |
| 303 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-gc', 'boehm', target], false) |
| 304 | assert prefs.gc_mode == .boehm_full_opt |
| 305 | assert prefs.build_options.contains('-gc boehm') |
| 306 | } |
| 307 | |
| 308 | fn test_cross_compile_defaults_windows_to_the_cross_compiler_arch() { |
| 309 | if pref.get_host_os() == .windows { |
| 310 | return |
| 311 | } |
| 312 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 313 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'windows', target], false) |
| 314 | assert prefs.arch == .amd64 |
| 315 | assert prefs.ccompiler == 'x86_64-w64-mingw32-gcc' |
| 316 | } |
| 317 | |
| 318 | fn test_cross_compile_windows_m32_uses_i386_arch_and_compiler() { |
| 319 | if pref.get_host_os() == .windows { |
| 320 | return |
| 321 | } |
| 322 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 323 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'windows', '-m32', target], false) |
| 324 | assert !prefs.m64 |
| 325 | assert prefs.arch == .i386 |
| 326 | assert prefs.ccompiler == 'i686-w64-mingw32-gcc' |
| 327 | assert prefs.build_options.contains('-m32') |
| 328 | } |
| 329 | |
| 330 | fn test_cross_compile_defaults_linux_to_amd64() { |
| 331 | if pref.get_host_os() == .linux { |
| 332 | return |
| 333 | } |
| 334 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 335 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'linux', target], false) |
| 336 | assert prefs.arch == .amd64 |
| 337 | assert prefs.ccompiler == 'clang' |
| 338 | } |
| 339 | |
| 340 | fn test_cross_compile_infers_android_arch_from_vcross_compiler_name() { |
| 341 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 342 | old_cross_compiler := os.getenv('VCROSS_COMPILER_NAME') |
| 343 | defer { |
| 344 | os.setenv('VCROSS_COMPILER_NAME', old_cross_compiler, true) |
| 345 | } |
| 346 | for compiler_name, expected_arch in { |
| 347 | 'aarch64-linux-android21-clang': pref.Arch.arm64 |
| 348 | 'armv7a-linux-androideabi21-clang': pref.Arch.arm32 |
| 349 | 'i686-linux-android21-clang': pref.Arch.i386 |
| 350 | 'x86_64-linux-android21-clang': pref.Arch.amd64 |
| 351 | } { |
| 352 | os.setenv('VCROSS_COMPILER_NAME', compiler_name, true) |
| 353 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-os', 'android', target], false) |
| 354 | assert prefs.arch == expected_arch |
| 355 | assert prefs.ccompiler == compiler_name |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | fn test_musl_still_defaults_to_boehm_gc() { |
| 360 | // Regression test for https://github.com/vlang/v/issues/27090 . |
| 361 | // Alpine/musl programs must keep the boehm GC by default; otherwise |
| 362 | // long-running allocations grow without bound (see the issue's repro). |
| 363 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 364 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-musl', target], false) |
| 365 | assert prefs.is_musl |
| 366 | assert prefs.gc_mode == .boehm_full_opt |
| 367 | } |
| 368 | |
| 369 | fn test_prealloc_defaults_to_no_gc() { |
| 370 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 371 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-prealloc', target], false) |
| 372 | assert prefs.prealloc |
| 373 | assert prefs.gc_mode == .no_gc |
| 374 | } |
| 375 | |
| 376 | fn test_prealloc_overrides_explicit_gc_selection() { |
| 377 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 378 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-gc', 'boehm', '-prealloc', target], |
| 379 | false) |
| 380 | assert prefs.prealloc |
| 381 | assert prefs.gc_mode == .no_gc |
| 382 | assert 'gcboehm' !in prefs.compile_defines |
| 383 | assert prefs.build_options.join(' ').contains('-gc none') |
| 384 | } |
| 385 | |
| 386 | fn test_no_gc_thread_local_alloc_prefers_source_bundled_boehm() { |
| 387 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 388 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-d', 'no_gc_thread_local_alloc', target], |
| 389 | false) |
| 390 | assert prefs.gc_mode == .boehm_full_opt |
| 391 | assert 'no_gc_thread_local_alloc' in prefs.compile_defines_all |
| 392 | assert 'use_bundled_libgc' in prefs.compile_defines_all |
| 393 | assert !prefs.ccompiler.contains('tcc') |
| 394 | assert prefs.build_options.contains('-d use_bundled_libgc') |
| 395 | } |
| 396 | |
| 397 | fn test_no_gc_thread_local_alloc_does_not_force_boehm_with_gc_none() { |
| 398 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 399 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-gc', 'none', '-d', |
| 400 | 'no_gc_thread_local_alloc', target], false) |
| 401 | assert prefs.gc_mode == .no_gc |
| 402 | assert 'no_gc_thread_local_alloc' in prefs.compile_defines_all |
| 403 | assert 'use_bundled_libgc' !in prefs.compile_defines_all |
| 404 | } |
| 405 | |
| 406 | fn test_no_gc_thread_local_alloc_keeps_explicit_dynamic_boehm() { |
| 407 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 408 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-d', 'dynamic_boehm', '-d', |
| 409 | 'no_gc_thread_local_alloc', target], false) |
| 410 | assert prefs.gc_mode == .boehm_full_opt |
| 411 | assert 'dynamic_boehm' in prefs.compile_defines_all |
| 412 | assert 'use_bundled_libgc' !in prefs.compile_defines_all |
| 413 | } |
| 414 | |
| 415 | fn stale_windows_gc_prefs(gc_set_by_flag bool) pref.Preferences { |
| 416 | mut prefs := pref.Preferences{ |
| 417 | os: .windows |
| 418 | ccompiler_type: .msvc |
| 419 | gc_mode: .boehm_full_opt |
| 420 | gc_set_by_flag: gc_set_by_flag |
| 421 | compile_defines: ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom'] |
| 422 | compile_defines_all: ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom'] |
| 423 | compile_values: map[string]string{} |
| 424 | build_options: ['-prod', '-d gcboehm', '-d gcboehm_full', '-d gcboehm_opt'] |
| 425 | } |
| 426 | prefs.compile_values['gcboehm'] = 'true' |
| 427 | prefs.compile_values['gcboehm_full'] = 'true' |
| 428 | prefs.compile_values['gcboehm_opt'] = 'true' |
| 429 | prefs.compile_values['custom'] = 'true' |
| 430 | return prefs |
| 431 | } |
| 432 | |
| 433 | fn test_windows_msvc_gc_defaults_are_cleared_after_compiler_resolution() { |
| 434 | mut prefs := stale_windows_gc_prefs(false) |
| 435 | |
| 436 | prefs.normalize_gc_defaults_for_resolved_ccompiler() |
| 437 | |
| 438 | assert prefs.gc_mode == .no_gc |
| 439 | assert prefs.build_options == ['-prod', '-gc', 'none'] |
| 440 | assert prefs.compile_defines == ['custom'] |
| 441 | assert prefs.compile_defines_all == ['custom'] |
| 442 | assert prefs.compile_values == { |
| 443 | 'custom': 'true' |
| 444 | } |
| 445 | } |
| 446 | |
| 447 | fn test_windows_msvc_gc_defaults_keep_explicit_gc_selection() { |
| 448 | mut prefs := stale_windows_gc_prefs(true) |
| 449 | prefs.build_options = ['-prod', '-gc', 'boehm', '-d gcboehm', '-d gcboehm_full', '-d gcboehm_opt'] |
| 450 | |
| 451 | prefs.normalize_gc_defaults_for_resolved_ccompiler() |
| 452 | |
| 453 | assert prefs.gc_mode == .boehm_full_opt |
| 454 | assert prefs.build_options == ['-prod', '-gc', 'boehm', '-d gcboehm', '-d gcboehm_full', |
| 455 | '-d gcboehm_opt'] |
| 456 | assert prefs.compile_defines == ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom'] |
| 457 | assert prefs.compile_defines_all == ['gcboehm', 'gcboehm_full', 'gcboehm_opt', 'custom'] |
| 458 | assert prefs.compile_values == { |
| 459 | 'custom': 'true' |
| 460 | 'gcboehm': 'true' |
| 461 | 'gcboehm_full': 'true' |
| 462 | 'gcboehm_opt': 'true' |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | fn test_m32_sets_i386_arch_when_not_explicitly_set() { |
| 467 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 468 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-m32', target], false) |
| 469 | assert !prefs.m64 |
| 470 | assert prefs.arch == .i386 |
| 471 | assert prefs.build_options.contains('-m32') |
| 472 | } |
| 473 | |
| 474 | fn test_m32_does_not_override_explicit_arch() { |
| 475 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 476 | prefs, _ := pref.parse_args_and_show_errors([], ['', '-arch', 'amd64', '-m32', target], false) |
| 477 | assert !prefs.m64 |
| 478 | assert prefs.arch == .amd64 |
| 479 | assert prefs.build_options.contains('-m32') |
| 480 | } |
| 481 | |
| 482 | fn test_v_cmds_and_flags() { |
| 483 | build_cmd_res := os.execute('${vexe} build ${vroot}/examples/hello_world.v') |
| 484 | assert build_cmd_res.output.trim_space() == 'Use `v ${vroot}/examples/hello_world.v` instead.' |
| 485 | |
| 486 | too_many_targets_res := |
| 487 | os.execute('${vexe} ${vroot}/examples/hello_world.v ${vroot}/examples/fizz_buzz.v') |
| 488 | assert too_many_targets_res.output.trim_space() == 'Too many targets. Specify just one target: <target.v|target_directory>.' |
| 489 | |
| 490 | unknown_arg_res := os.execute('${vexe} -xyz') |
| 491 | assert unknown_arg_res.output.trim_space() == 'Unknown argument `-xyz`' |
| 492 | |
| 493 | unknown_arg_for_cmd_res := os.execute('${vexe} build-module -xyz ${vroot}/vlib/math') |
| 494 | assert unknown_arg_for_cmd_res.output.trim_space() == 'Unknown argument `-xyz` for command `build-module`' |
| 495 | |
| 496 | v2_only_flag_without_v2_res := |
| 497 | os.execute('${vexe} --skip-builtin ${vroot}/examples/hello_world.v') |
| 498 | assert v2_only_flag_without_v2_res.exit_code == 1 |
| 499 | assert v2_only_flag_without_v2_res.output.trim_space() == 'Unknown argument `--skip-builtin`' |
| 500 | |
| 501 | v2_hooks_without_v2_res := os.execute('${vexe} -fhooks output ${vroot}/examples/hello_world.v') |
| 502 | assert v2_hooks_without_v2_res.exit_code == 1 |
| 503 | assert v2_hooks_without_v2_res.output.trim_space() == 'Unknown argument `-fhooks`' |
| 504 | |
| 505 | v2_os_none_without_v2_res := os.execute('${vexe} -os none ${vroot}/examples/hello_world.v') |
| 506 | assert v2_os_none_without_v2_res.exit_code == 1 |
| 507 | assert v2_os_none_without_v2_res.output.trim_space() == 'unknown operating system target `none`' |
| 508 | |
| 509 | late_v2_skip_builtin_res := |
| 510 | os.execute('${vexe} --skip-builtin run ${vroot}/examples/hello_world.v -v2') |
| 511 | assert late_v2_skip_builtin_res.exit_code == 1 |
| 512 | assert late_v2_skip_builtin_res.output.trim_space() == 'Unknown argument `--skip-builtin`' |
| 513 | |
| 514 | late_v2_hooks_res := |
| 515 | os.execute('${vexe} -fhooks output run ${vroot}/examples/hello_world.v -v2') |
| 516 | assert late_v2_hooks_res.exit_code == 1 |
| 517 | assert late_v2_hooks_res.output.trim_space() == 'Unknown argument `-fhooks`' |
| 518 | |
| 519 | eval_removed_message := 'use v -v2 -eval file.v' |
| 520 | eval_flag_res := os.execute('${vexe} -eval ${vroot}/examples/hello_world.v') |
| 521 | assert eval_flag_res.exit_code == 1 |
| 522 | assert eval_flag_res.output.trim_space() == eval_removed_message |
| 523 | |
| 524 | eval_backend_res := os.execute('${vexe} -backend eval ${vroot}/examples/hello_world.v') |
| 525 | assert eval_backend_res.exit_code == 1 |
| 526 | assert eval_backend_res.output.trim_space() == eval_removed_message |
| 527 | |
| 528 | interpret_flag_res := os.execute('${vexe} -interpret ${vroot}/examples/hello_world.v') |
| 529 | assert interpret_flag_res.exit_code == 1 |
| 530 | assert interpret_flag_res.output.trim_space() == eval_removed_message |
| 531 | |
| 532 | interpret_command_res := os.execute('${vexe} interpret ${vroot}/examples/hello_world.v') |
| 533 | assert interpret_command_res.exit_code == 1 |
| 534 | assert interpret_command_res.output.trim_space() == eval_removed_message |
| 535 | |
| 536 | no_run_files_res := os.execute('${vexe} run') |
| 537 | assert no_run_files_res.output.trim_space() == 'v run: no v files listed' |
| 538 | |
| 539 | no_bm_files_res := os.execute('${vexe} build-module') |
| 540 | assert no_bm_files_res.output.trim_space() == 'v build-module: no module specified' |
| 541 | } |
| 542 | |
| 543 | fn test_build_command_compiles_vsh_without_running_it() { |
| 544 | test_dir := os.join_path(os.vtmp_dir(), 'v_pref_build_vsh_${os.getpid()}') |
| 545 | os.rmdir_all(test_dir) or {} |
| 546 | os.mkdir_all(test_dir)! |
| 547 | defer { |
| 548 | os.rmdir_all(test_dir) or {} |
| 549 | } |
| 550 | script_path := os.join_path(test_dir, 'build_only.vsh') |
| 551 | marker_path := os.join_path(test_dir, 'marker.txt') |
| 552 | mut exe_path := os.join_path(test_dir, 'build_only') |
| 553 | $if windows { |
| 554 | exe_path += '.exe' |
| 555 | } |
| 556 | os.write_file(script_path, "import os |
| 557 | |
| 558 | fn main() { |
| 559 | marker_path := os.join_path(@DIR, 'marker.txt') |
| 560 | os.write_file(marker_path, 'ran') or { panic(err) } |
| 561 | println('ran') |
| 562 | } |
| 563 | ")! |
| 564 | build_res := os.execute('${os.quoted_path(vexe)} -silent build ${os.quoted_path(script_path)}') |
| 565 | assert build_res.exit_code == 0, build_res.output |
| 566 | assert build_res.output == '' |
| 567 | assert !os.exists(marker_path) |
| 568 | assert os.is_file(exe_path) |
| 569 | |
| 570 | run_res := os.execute(os.quoted_path(exe_path)) |
| 571 | assert run_res.exit_code == 0, run_res.output |
| 572 | assert run_res.output.trim_space() == 'ran' |
| 573 | assert os.read_file(marker_path)! == 'ran' |
| 574 | } |
| 575 | |
| 576 | const tfile = os.join_path(os.vtmp_dir(), 'unknown_options_output.c') |
| 577 | |
| 578 | fn test_unknown_option_flags_no_run() { |
| 579 | os.chdir(os.dir(@VEXE))! |
| 580 | os.rm(tfile) or {} |
| 581 | |
| 582 | res1 := |
| 583 | os.execute('${os.quoted_path(@VEXE)} -o ${os.quoted_path(tfile)} examples/hello_world.v --an-unknown-option') |
| 584 | assert res1.exit_code == 1, res1.output |
| 585 | assert res1.output.starts_with('Unknown argument') |
| 586 | assert res1.output.contains('--an-unknown-option') |
| 587 | assert !os.exists(tfile) |
| 588 | |
| 589 | res2 := |
| 590 | os.execute('${os.quoted_path(@VEXE)} -o ${os.quoted_path(tfile)} --an-unknown-option examples/hello_world.v') |
| 591 | assert res2.exit_code == 1, res2.output |
| 592 | assert res2.output.starts_with('Unknown argument') |
| 593 | assert res2.output.contains('--an-unknown-option') |
| 594 | assert !os.exists(tfile) |
| 595 | } |
| 596 | |
| 597 | fn test_unknown_option_flags_with_run() { |
| 598 | res_run_o := |
| 599 | os.execute('${os.quoted_path(@VEXE)} -o ${os.quoted_path(tfile)} run examples/hello_world.v --an-unknown-option') |
| 600 | assert res_run_o.exit_code == 0, res_run_o.output |
| 601 | assert res_run_o.output == '' // because of -o, there should not be an actual run, since compilation stopped after generating the .c file |
| 602 | assert os.exists(tfile) |
| 603 | os.rm(tfile) or {} |
| 604 | |
| 605 | res_run_no_o_unknown_before_run := |
| 606 | os.execute('${os.quoted_path(@VEXE)} --an-unknown-option run examples/hello_world.v ') |
| 607 | assert res_run_no_o_unknown_before_run.exit_code == 1, res_run_no_o_unknown_before_run.output |
| 608 | assert res_run_no_o_unknown_before_run.output.starts_with('Unknown argument') |
| 609 | assert res_run_no_o_unknown_before_run.output.contains('--an-unknown-option') |
| 610 | assert !os.exists(tfile) |
| 611 | |
| 612 | res_run_no_o := |
| 613 | os.execute('${os.quoted_path(@VEXE)} run examples/hello_world.v --an-unknown-option') |
| 614 | assert res_run_no_o.exit_code == 0, res_run_no_o.output |
| 615 | assert res_run_no_o.output.trim_space() == 'Hello, World!' |
| 616 | assert !os.exists(tfile) |
| 617 | } |
| 618 | |
| 619 | fn test_missing_explicit_ccompiler_reports_error() { |
| 620 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 621 | missing_cc := 'missing_compiler_17126_for_pref_test' |
| 622 | output := os.join_path(os.vtmp_dir(), 'missing_explicit_ccompiler_output') |
| 623 | mut expected_output := output |
| 624 | $if windows { |
| 625 | expected_output += '.exe' |
| 626 | } |
| 627 | os.rm(expected_output) or {} |
| 628 | res := |
| 629 | os.execute('${os.quoted_path(@VEXE)} -cc ${missing_cc} -o ${os.quoted_path(output)} ${os.quoted_path(target)}') |
| 630 | assert res.exit_code != 0 |
| 631 | assert res.output.contains(missing_cc), res.output |
| 632 | assert res.output.to_lower().contains('not found') || res.output.to_lower().contains('missing'), res.output |
| 633 | |
| 634 | assert !os.exists(expected_output) |
| 635 | } |
| 636 | |
| 637 | fn test_generate_c_project_flag_parsing() { |
| 638 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 639 | prefs, _ := pref.parse_args_and_show_errors([], ['-generate-c-project', 'cproj', target], false) |
| 640 | assert prefs.generate_c_project == 'cproj' |
| 641 | assert prefs.use_cache == false |
| 642 | } |
| 643 | |
| 644 | fn test_generate_c_project_creates_build_files() { |
| 645 | output_dir := os.join_path(os.vtmp_dir(), 'v_generate_c_project_json') |
| 646 | os.rmdir_all(output_dir) or {} |
| 647 | defer { |
| 648 | os.rmdir_all(output_dir) or {} |
| 649 | } |
| 650 | target := os.join_path(vroot, 'examples', 'json.v') |
| 651 | cmd := '${os.quoted_path(vexe)} -generate-c-project ${os.quoted_path(output_dir)} ${os.quoted_path(target)}' |
| 652 | res := os.execute(cmd) |
| 653 | assert res.exit_code == 0, res.output |
| 654 | for rel_path in ['json.c', 'build_command.txt', 'build.sh', 'build.bat', 'Makefile'] { |
| 655 | assert os.is_file(os.join_path(output_dir, rel_path)) |
| 656 | } |
| 657 | build_command := os.read_file(os.join_path(output_dir, 'build_command.txt')) or { panic(err) } |
| 658 | generated_c_path := os.join_path(output_dir, 'json.c') |
| 659 | normalized_build_command := normalized_build_path(build_command) |
| 660 | assert normalized_build_command.contains(normalized_build_path(generated_c_path)) |
| 661 | || normalized_build_command.contains(normalized_build_path(os.short_path(generated_c_path))) |
| 662 | assert build_command.contains('cJSON.c') |
| 663 | assert !build_command.contains('.tmp.c') |
| 664 | assert !build_command.contains('.module.') |
| 665 | } |
| 666 | |
| 667 | fn normalized_build_path(path string) string { |
| 668 | mut normalized := path.replace('\\', '/') |
| 669 | for normalized.contains('//') { |
| 670 | normalized = normalized.replace('//', '/') |
| 671 | } |
| 672 | return normalized |
| 673 | } |
| 674 | |
| 675 | fn test_output_flag_accepts_directory_path() { |
| 676 | output_dir := os.join_path(os.vtmp_dir(), 'v_output_flag_directory') |
| 677 | os.rmdir_all(output_dir) or {} |
| 678 | defer { |
| 679 | os.rmdir_all(output_dir) or {} |
| 680 | } |
| 681 | target := os.join_path(vroot, 'examples', 'hello_world.v') |
| 682 | output_arg := output_dir + os.path_separator |
| 683 | res := |
| 684 | os.execute('${os.quoted_path(vexe)} -o ${os.quoted_path(output_arg)} ${os.quoted_path(target)}') |
| 685 | assert res.exit_code == 0, res.output |
| 686 | assert os.is_dir(output_dir) |
| 687 | mut expected_output := os.join_path(output_dir, 'hello_world') |
| 688 | $if windows { |
| 689 | expected_output += '.exe' |
| 690 | } |
| 691 | assert os.is_file(expected_output) |
| 692 | } |
| 693 | |
| 694 | fn test_tcc_shared_builds_disable_backtraces() { |
| 695 | mut shared_prefs := &pref.Preferences{ |
| 696 | path: 'libfoo.v' |
| 697 | is_shared: true |
| 698 | ccompiler: 'tinyc' |
| 699 | } |
| 700 | shared_prefs.fill_with_defaults() |
| 701 | assert 'no_backtrace' in shared_prefs.compile_defines_all |
| 702 | |
| 703 | mut regular_prefs := &pref.Preferences{ |
| 704 | path: 'main.v' |
| 705 | ccompiler: 'tinyc' |
| 706 | } |
| 707 | regular_prefs.fill_with_defaults() |
| 708 | assert 'no_backtrace' !in regular_prefs.compile_defines_all |
| 709 | } |
| 710 | |
| 711 | fn test_bsd_tinyc_defaults_to_openssl() { |
| 712 | mut bsd_tinyc_prefs := &pref.Preferences{ |
| 713 | path: 'main.v' |
| 714 | os: .freebsd |
| 715 | ccompiler: 'tinyc' |
| 716 | ccompiler_set_by_flag: true |
| 717 | } |
| 718 | bsd_tinyc_prefs.fill_with_defaults() |
| 719 | assert 'use_openssl' in bsd_tinyc_prefs.compile_defines |
| 720 | assert 'use_openssl' in bsd_tinyc_prefs.compile_defines_all |
| 721 | |
| 722 | mut bsd_clang_prefs := &pref.Preferences{ |
| 723 | path: 'main.v' |
| 724 | os: .freebsd |
| 725 | ccompiler: 'clang' |
| 726 | } |
| 727 | bsd_clang_prefs.fill_with_defaults() |
| 728 | assert 'use_openssl' !in bsd_clang_prefs.compile_defines_all |
| 729 | } |
| 730 | |
| 731 | fn test_late_resolved_tcc_shared_builds_disable_backtraces() { |
| 732 | mut shared_prefs := &pref.Preferences{ |
| 733 | path: 'libfoo.v' |
| 734 | is_shared: true |
| 735 | ccompiler: 'gcc' |
| 736 | } |
| 737 | shared_prefs.fill_with_defaults() |
| 738 | assert 'no_backtrace' !in shared_prefs.compile_defines_all |
| 739 | |
| 740 | shared_prefs.ccompiler_type = .tinyc |
| 741 | shared_prefs.normalize_gc_defaults_for_resolved_ccompiler() |
| 742 | |
| 743 | assert 'no_backtrace' in shared_prefs.compile_defines_all |
| 744 | assert shared_prefs.build_options.contains('-d no_backtrace') |
| 745 | } |
| 746 | |
| 747 | fn test_wayland_only_linux_session_surfaces_a_v_error_for_gg() { |
| 748 | if os.user_os() == 'windows' { |
| 749 | return |
| 750 | } |
| 751 | pid := os.getpid() |
| 752 | test_dir := os.join_path(os.vtmp_dir(), 'v_issue_18030_gg_wayland_${pid}') |
| 753 | source_path := os.join_path(test_dir, 'main.v') |
| 754 | exe_path := os.join_path(test_dir, 'app') |
| 755 | source := 'import gg as _\n\nfn main() {}\n' |
| 756 | os.mkdir_all(test_dir) or { panic(err) } |
| 757 | os.write_file(source_path, source) or { panic(err) } |
| 758 | defer { |
| 759 | os.rmdir_all(test_dir) or {} |
| 760 | } |
| 761 | 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)}' |
| 762 | res := os.execute(cmd) |
| 763 | output := res.output.replace('\r', '') |
| 764 | if res.exit_code == 0 { |
| 765 | eprintln('> failed command: ${cmd}') |
| 766 | } |
| 767 | assert res.exit_code != 0 |
| 768 | assert output.contains('Wayland-only Linux session without `-d sokol_wayland`') |
| 769 | assert !output.contains('C error. This should never happen.') |
| 770 | } |
| 771 | |