v4 / cmd / v / vvm_test.v
291 lines · 268 sloc · 10.09 KB · e8810a671233f1d2072d70ab8e17c3b1dad5e1e5
Raw
1module main
2
3import os
4import rand
5
6const current_vexe = @VEXE
7
8const delegated_marker = 'VVM-DELEGATED'
9
10const delegated_v2_marker = 'V2-DELEGATED-WAITED'
11
12const requested_vvm_test_version = '99.99.99'
13
14struct CmdResult {
15 exit_code int
16 output string
17}
18
19fn vvm_test_repo_root() string {
20 mut dir := os.dir(@FILE)
21 for _ in 0 .. 10 {
22 if os.exists(os.join_path(dir, 'cmd', 'v', 'v.v'))
23 && os.exists(os.join_path(dir, 'vlib', 'builtin')) {
24 return dir
25 }
26 dir = os.dir(dir)
27 }
28 panic('could not locate repo root for vvm tests')
29}
30
31fn build_current_v_wrapper(tmp_root string) string {
32 vroot := vvm_test_repo_root()
33 wrapper_exe := os.join_path(tmp_root, if os.user_os() == 'windows' {
34 'v_public_wrapper.exe'
35 } else {
36 'v_public_wrapper'
37 })
38 compile_res := os.execute('${os.quoted_path(current_vexe)} -path "${os.join_path(vroot, 'vlib')}|@vlib|@vmodules" -o ${os.quoted_path(wrapper_exe)} ${os.quoted_path(os.join_path(vroot,
39 'cmd', 'v'))}')
40 assert compile_res.exit_code == 0, compile_res.output
41 return wrapper_exe
42}
43
44fn test_parse_vvmrc_version() {
45 assert parse_vvmrc_version('') == ''
46 assert parse_vvmrc_version(' ') == ''
47 assert parse_vvmrc_version('# only comments') == ''
48 assert parse_vvmrc_version('\n# comment\n0.4.6\n') == '0.4.6'
49 assert parse_vvmrc_version(' latest # comment ') == 'latest'
50}
51
52fn test_find_project_vvmrc_stops_at_stop_paths() {
53 tmp_root := os.join_path(os.vtmp_dir(), 'vvmrc_stop_test_${rand.ulid()}')
54 os.mkdir_all(tmp_root) or { panic(err) }
55 defer {
56 os.rmdir_all(tmp_root) or {}
57 }
58 project_dir := os.join_path(tmp_root, 'project')
59 source_dir := os.join_path(project_dir, 'src')
60 os.mkdir_all(source_dir) or { panic(err) }
61 os.mkdir_all(os.join_path(project_dir, '.git')) or { panic(err) }
62 os.write_file(os.join_path(tmp_root, '.vvmrc'), requested_vvm_test_version) or { panic(err) }
63 main_v := os.join_path(source_dir, 'main.v')
64 os.write_file(main_v, 'fn main() {}') or { panic(err) }
65 assert find_project_vvmrc(main_v) == ''
66 local_vvmrc := os.join_path(project_dir, '.vvmrc')
67 os.write_file(local_vvmrc, requested_vvm_test_version) or { panic(err) }
68 assert find_project_vvmrc(main_v) == os.real_path(local_vvmrc)
69}
70
71fn test_vvmrc_delegates_to_matching_compiler_executable() {
72 tmp_root := os.join_path(os.vtmp_dir(), 'vvmrc_delegate_test_${rand.ulid()}')
73 os.mkdir_all(tmp_root) or { panic(err) }
74 defer {
75 os.rmdir_all(tmp_root) or {}
76 }
77 bin_dir := os.join_path(tmp_root, 'bin')
78 os.mkdir_all(bin_dir) or { panic(err) }
79 fake_compiler_source := os.join_path(tmp_root, 'fake_compiler.v')
80 os.write_file(fake_compiler_source,
81 "import os\nfn main() {\n\tprintln('${delegated_marker} ' + os.args[1..].join(' '))\n}\n") or {
82 panic(err)
83 }
84 fake_compiler_exe := os.join_path(bin_dir, if os.user_os() == 'windows' {
85 'v${requested_vvm_test_version}.exe'
86 } else {
87 'v${requested_vvm_test_version}'
88 })
89 compile_res :=
90 os.execute('${os.quoted_path(current_vexe)} -o ${os.quoted_path(fake_compiler_exe)} ${os.quoted_path(fake_compiler_source)}')
91 assert compile_res.exit_code == 0, compile_res.output
92 project_dir := os.join_path(tmp_root, 'project')
93 os.mkdir_all(project_dir) or { panic(err) }
94 os.write_file(os.join_path(project_dir, '.vvmrc'), requested_vvm_test_version) or { panic(err) }
95 os.write_file(os.join_path(project_dir, 'main.v'),
96 "fn main() {\n\tprintln('from project')\n}\n") or { panic(err) }
97 mut envs := os.environ()
98 path_key := find_path_env_key(envs)
99 envs[path_key] = '${bin_dir}${os.path_delimiter}${envs[path_key]}'
100 envs['V_SKIP_VVMRC'] = ''
101 res := run_v_command(project_dir, ['run', 'main.v'], envs)
102 assert res.exit_code == 0, res.output
103 assert res.output.contains('${delegated_marker} run main.v'), res.output
104}
105
106fn test_v2_delegation_waits_for_compiler_process_and_propagates_exit_code() {
107 tmp_root := os.join_path(os.vtmp_dir(), 'v2_delegate_wait_test_${rand.ulid()}')
108 os.mkdir_all(tmp_root) or { panic(err) }
109 defer {
110 os.rmdir_all(tmp_root) or {}
111 }
112 fake_compiler_source := os.join_path(tmp_root, 'fake_v2_compiler.v')
113 marker_file := os.join_path(tmp_root, 'v2_marker.txt')
114 os.write_file(fake_compiler_source,
115 "import os\nimport time\nfn main() {\n\ttime.sleep(700 * time.millisecond)\n\tmarker := os.getenv('V_V2_TEST_MARKER')\n\tos.write_file(marker, os.args[1..].join(' ')) or { panic(err) }\n\tprintln('${delegated_v2_marker}')\n\texit(7)\n}\n") or {
116 panic(err)
117 }
118 fake_compiler_exe := os.join_path(tmp_root, if os.user_os() == 'windows' {
119 'fake_v2_compiler.exe'
120 } else {
121 'fake_v2_compiler'
122 })
123 compile_res :=
124 os.execute('${os.quoted_path(current_vexe)} -o ${os.quoted_path(fake_compiler_exe)} ${os.quoted_path(fake_compiler_source)}')
125 assert compile_res.exit_code == 0, compile_res.output
126 project_dir := os.join_path(tmp_root, 'project')
127 os.mkdir_all(project_dir) or { panic(err) }
128 os.write_file(os.join_path(project_dir, 'main.v'), "fn main() {\n\tprintln('unused')\n}\n") or {
129 panic(err)
130 }
131 mut envs := os.environ()
132 envs[delegated_v2_exe_env] = fake_compiler_exe
133 envs['V_V2_TEST_MARKER'] = marker_file
134 envs[vvmrc_skip_env] = '1'
135 envs['VFLAGS'] = ''
136
137 res := run_v_command(project_dir, ['-v2', 'main.v'], envs)
138 assert res.exit_code == 7, res.output
139 assert res.output.contains(delegated_v2_marker), res.output
140 assert os.is_file(marker_file)
141 marker := os.read_file(marker_file) or { panic(err) }
142 assert marker.contains('main.v'), marker
143 assert !marker.contains('-v2'), marker
144}
145
146fn test_v2_delegation_forwards_target_specific_flags() {
147 tmp_root := os.join_path(os.vtmp_dir(), 'v2_delegate_flags_test_${rand.ulid()}')
148 os.mkdir_all(tmp_root) or { panic(err) }
149 defer {
150 os.rmdir_all(tmp_root) or {}
151 }
152 fake_compiler_source := os.join_path(tmp_root, 'fake_v2_compiler.v')
153 marker_file := os.join_path(tmp_root, 'v2_args.txt')
154 os.write_file(fake_compiler_source,
155 "import os\nfn main() {\n\tmarker := os.getenv('V_V2_TEST_MARKER')\n\tos.write_file(marker, os.args[1..].join(' ')) or { panic(err) }\n}\n") or {
156 panic(err)
157 }
158 fake_compiler_exe := os.join_path(tmp_root, if os.user_os() == 'windows' {
159 'fake_v2_compiler.exe'
160 } else {
161 'fake_v2_compiler'
162 })
163 compile_res :=
164 os.execute('${os.quoted_path(current_vexe)} -o ${os.quoted_path(fake_compiler_exe)} ${os.quoted_path(fake_compiler_source)}')
165 assert compile_res.exit_code == 0, compile_res.output
166 project_dir := os.join_path(tmp_root, 'project')
167 os.mkdir_all(project_dir) or { panic(err) }
168 os.write_file(os.join_path(project_dir, 'main.v'), 'fn main() {}\n') or { panic(err) }
169 wrapper_exe := build_current_v_wrapper(tmp_root)
170 mut envs := os.environ()
171 envs[delegated_v2_exe_env] = fake_compiler_exe
172 envs['V_V2_TEST_MARKER'] = marker_file
173 envs[vvmrc_skip_env] = '1'
174 envs['VFLAGS'] = ''
175 envs['VEXE'] = os.join_path(vvm_test_repo_root(), 'v')
176
177 res := run_v_command_with_exe(wrapper_exe, project_dir, [
178 '-v2',
179 '-freestanding',
180 '-os',
181 'none',
182 '--skip-builtin',
183 '--skip-type-check',
184 '-fhooks',
185 'output,panic,alloc',
186 '-o',
187 'out.c',
188 'main.v',
189 ], envs)
190 assert res.exit_code == 0, res.output
191 assert os.is_file(marker_file)
192 marker := os.read_file(marker_file) or { panic(err) }
193 assert marker.contains('-freestanding'), marker
194 assert marker.contains('-os none'), marker
195 assert marker.contains('--skip-builtin'), marker
196 assert marker.contains('--skip-type-check'), marker
197 assert marker.contains('-fhooks output,panic,alloc'), marker
198 assert marker.contains('-o out.c'), marker
199 assert marker.contains('main.v'), marker
200 assert !marker.contains('-v2'), marker
201
202 res_macos := run_v_command_with_exe(wrapper_exe, project_dir, [
203 '-v2',
204 '-b',
205 'x64',
206 '-os',
207 'macos',
208 '-no-mos-tiny',
209 '-o',
210 'out',
211 'main.v',
212 ], envs)
213 assert res_macos.exit_code == 0, res_macos.output
214 macos_marker := os.read_file(marker_file) or { panic(err) }
215 assert macos_marker.contains('-b x64'), macos_marker
216 assert macos_marker.contains('-os macos'), macos_marker
217 assert macos_marker.contains('-no-mos-tiny'), macos_marker
218 assert macos_marker.contains('-o out'), macos_marker
219 assert macos_marker.contains('main.v'), macos_marker
220 assert !macos_marker.contains('-v2'), macos_marker
221
222 os.rm(marker_file) or {}
223 legacy_macos_tiny_res := run_v_command_with_exe(wrapper_exe, project_dir, [
224 '-v2',
225 '-mos-tiny',
226 'main.v',
227 ], envs)
228 assert legacy_macos_tiny_res.exit_code == 1, legacy_macos_tiny_res.output
229 assert legacy_macos_tiny_res.output.contains('Unknown argument `-mos-tiny`'), legacy_macos_tiny_res.output
230 assert !os.exists(marker_file), 'legacy -mos-tiny was forwarded to V2'
231
232 for blocked_args in [
233 ['--skip-builtin', '--', '-v2', 'main.v'],
234 ['--skip-builtin', 'run', 'main.v', '-v2'],
235 ['main.v', '--skip-builtin', '-v2'],
236 ] {
237 blocked_res := run_v_command_with_exe(wrapper_exe, project_dir, blocked_args, envs)
238 assert blocked_res.exit_code == 1, blocked_res.output
239 assert blocked_res.output.contains('Unknown argument `--skip-builtin`'), blocked_res.output
240 }
241
242 late_hooks_res := run_v_command_with_exe(wrapper_exe, project_dir, [
243 '-fhooks',
244 'output',
245 'run',
246 'main.v',
247 '-v2',
248 ], envs)
249 assert late_hooks_res.exit_code == 1, late_hooks_res.output
250 assert late_hooks_res.output.contains('Unknown argument `-fhooks`'), late_hooks_res.output
251
252 os_none_after_run_res := run_v_command_with_exe(wrapper_exe, project_dir, [
253 '-os',
254 'none',
255 'run',
256 'main.v',
257 '-v2',
258 ], envs)
259 assert os_none_after_run_res.exit_code == 1, os_none_after_run_res.output
260 assert os_none_after_run_res.output.contains('unknown operating system target `none`'), os_none_after_run_res.output
261}
262
263fn run_v_command(work_dir string, args []string, envs map[string]string) CmdResult {
264 return run_v_command_with_exe(current_vexe, work_dir, args, envs)
265}
266
267fn run_v_command_with_exe(vexe string, work_dir string, args []string, envs map[string]string) CmdResult {
268 mut process := os.new_process(vexe)
269 process.set_work_folder(work_dir)
270 process.set_args(args)
271 process.set_environment(envs)
272 process.set_redirect_stdio()
273 process.wait()
274 output := process.stdout_slurp() + process.stderr_slurp()
275 exit_code := if process.code == -1 { 1 } else { process.code }
276 process.close()
277 return CmdResult{
278 exit_code: exit_code
279 output: output
280 }
281}
282
283fn find_path_env_key(envs map[string]string) string {
284 if 'PATH' in envs {
285 return 'PATH'
286 }
287 if 'Path' in envs {
288 return 'Path'
289 }
290 return 'PATH'
291}
292