v2 / vlib / v / tests / projects_that_should_compile_test.v
365 lines · 338 sloc · 11.37 KB · da7e85cbec7fd73d9d26db033850648c49120c9f
Raw
1import os
2
3fn testsuite_begin() {
4 os.setenv('VCOLORS', 'never', true)
5 // TODO: remove this, when after vc/v.c *also* uses `_cache`, instead of `cache`:
6 old_cache_path := os.join_path(os.vmodules_dir(), 'cache')
7 dump(old_cache_path)
8 if os.exists(old_cache_path) {
9 os.rmdir_all(old_cache_path)!
10 }
11}
12
13fn vroot_path(relpath string) string {
14 return os.real_path(os.join_path(@VMODROOT, relpath))
15}
16
17fn vrun_ok_in_dir(workdir string, options string, path string) string {
18 old_wd := os.getwd()
19 os.chdir(workdir) or { panic(err) }
20 defer {
21 os.chdir(old_wd) or { panic(err) }
22 }
23 return vrun_ok(options, path)
24}
25
26fn write_file(path string, content string) {
27 os.write_file(path, content) or { panic(err) }
28}
29
30fn setup_module_resolution_workdir_fixture() string {
31 workspace := os.join_path(os.vtmp_dir(),
32 'v_module_resolution_independent_of_workdir_${os.getpid()}')
33 interp := r'${'
34 os.rmdir_all(workspace) or {}
35 os.mkdir_all(os.join_path(workspace, 'app')) or { panic(err) }
36 os.mkdir_all(os.join_path(workspace, 'lib')) or { panic(err) }
37 write_file(os.join_path(workspace, '.v.mod.stop'), '')
38 write_file(os.join_path(workspace, 'app', 'v.mod'),
39 "Module {\n\tname: 'app'\n\tdescription: ''\n\tversion: ''\n\tlicense: ''\n\tdependencies: []\n}\n")
40 write_file(os.join_path(workspace, 'app', 'main.v'),
41 "module main\n\nimport lib\n\nfn main() {\n\tprintln('Hello ${interp}lib.square(4)}!')\n}\n")
42 write_file(os.join_path(workspace, 'lib', 'v.mod'),
43 "Module {\n\tname: 'lib'\n\tdescription: ''\n\tversion: ''\n\tlicense: ''\n\tdependencies: []\n}\n")
44 write_file(os.join_path(workspace, 'lib', 'lib.v'),
45 'module lib\n\npub fn square(x int) int {\n\treturn x * x\n}\n')
46 return workspace
47}
48
49fn vrun_ok(options string, path string) string {
50 cmd := '${os.quoted_path(@VEXE)} ${options} ${os.quoted_path(path)}'
51 res := os.execute(cmd)
52 if res.exit_code != 0 {
53 eprintln('> failing vrun cmd: ${cmd}')
54 eprintln('> output:\n${res.output}')
55 assert res.exit_code == 0
56 }
57 return res.output
58}
59
60fn test_projects_should_run() {
61 $if windows {
62 return
63 }
64 res := vrun_ok('run', vroot_path('vlib/v/tests/testdata/enum_in_builtin') + os.path_separator)
65 assert res.trim_space() == 'v0'
66}
67
68fn test_running_subdir_project_with_parent_vmod_works() {
69 root := os.join_path(os.vtmp_dir(), 'v_subdir_project_with_parent_vmod')
70 os.rmdir_all(root) or {}
71 defer {
72 os.rmdir_all(root) or {}
73 }
74 os.mkdir_all(os.join_path(root, 'hexagonal', 'application'))!
75 os.write_file(os.join_path(root, 'v.mod'), 'Module {\nname: "vanilla3"\n}')!
76 os.write_file(os.join_path(root, 'hexagonal', 'application', 'auth_usecase.v'),
77 'module application\n\npub struct AuthUseCase {}\n')!
78 os.write_file(os.join_path(root, 'hexagonal', 'main.v'),
79 "module main\n\nimport application\n\nfn main() {\n\t_ := application.AuthUseCase{}\n\tprintln('built')\n}\n")!
80 old_dir := os.getwd()
81 defer {
82 os.chdir(old_dir) or {}
83 }
84 os.chdir(root)!
85 res := os.execute('${os.quoted_path(@VEXE)} run hexagonal')
86 assert res.exit_code == 0, res.output
87 assert res.output.trim_space() == 'built'
88}
89
90fn test_running_module_with_same_module_subdirs_setting_works() {
91 root := os.join_path(os.vtmp_dir(), 'v_same_module_subdirs_${os.getpid()}')
92 os.rmdir_all(root) or {}
93 defer {
94 os.rmdir_all(root) or {}
95 }
96 os.mkdir_all(os.join_path(root, 'app', 'foo', 'internal', 'nested'))!
97 os.write_file(os.join_path(root, 'app', 'main.v'),
98 'module main\n\nimport foo\n\nfn main() {\n\tprintln(foo.answer())\n}\n')!
99 os.write_file(os.join_path(root, 'app', 'foo', 'v.mod'),
100 "Module {\n\tname: 'foo'\n\tsubdirs: ['internal']\n}\n")!
101 os.write_file(os.join_path(root, 'app', 'foo', 'foo.v'),
102 'module foo\n\npub fn answer() int {\n\treturn secret()\n}\n')!
103 os.write_file(os.join_path(root, 'app', 'foo', 'internal', 'nested', 'secret.v'),
104 'module foo\n\nfn secret() int {\n\treturn 42\n}\n')!
105 old_dir := os.getwd()
106 defer {
107 os.chdir(old_dir) or {}
108 }
109 os.chdir(root)!
110 res := os.execute('${os.quoted_path(@VEXE)} run app/main.v')
111 assert res.exit_code == 0, res.output
112 assert res.output.trim_space() == '42'
113}
114
115fn test_running_project_with_same_module_subdirs_can_find_templates_next_to_vmod() {
116 root := os.join_path(os.vtmp_dir(), 'v_same_module_subdirs_veb_templates_${os.getpid()}')
117 os.rmdir_all(root) or {}
118 defer {
119 os.rmdir_all(root) or {}
120 }
121 os.mkdir_all(os.join_path(root, 'user'))!
122 os.mkdir_all(os.join_path(root, 'ci'))!
123 os.mkdir_all(os.join_path(root, 'templates'))!
124 os.write_file(os.join_path(root, 'v.mod'),
125 "Module {\n\tname: 'vebsubdirs'\n\tsubdirs: ['user', 'ci']\n}\n")!
126 os.write_file(os.join_path(root, 'main.v'), 'import veb
127
128pub struct App {}
129
130pub struct Context {
131 veb.Context
132}
133
134fn main() {}
135')!
136 os.write_file(os.join_path(root, 'user', 'register.v'), 'module main
137
138import veb
139
140@["/register"]
141pub fn (mut app App) register(mut ctx Context) veb.Result {
142 return $veb.html()
143}
144
145@["/settings"]
146pub fn (mut app App) settings(mut ctx Context) veb.Result {
147 return $veb.html("templates/settings.html")
148}
149')!
150 os.write_file(os.join_path(root, 'ci', 'ci_routes.v'), 'module main
151
152import veb
153
154@["/ci"]
155pub fn (mut app App) ci_runs(mut ctx Context) veb.Result {
156 return $veb.html()
157}
158')!
159 os.write_file(os.join_path(root, 'templates', 'register.html'),
160 '<html><body><p>Register</p></body></html>\n')!
161 os.write_file(os.join_path(root, 'templates', 'ci_runs.html'),
162 '<html><body><p>CI Runs</p></body></html>\n')!
163 os.write_file(os.join_path(root, 'templates', 'settings.html'),
164 '<html><body><p>Settings</p></body></html>\n')!
165 old_dir := os.getwd()
166 defer {
167 os.chdir(old_dir) or {}
168 }
169 os.chdir(root)!
170 res := os.execute('${os.quoted_path(@VEXE)} .')
171 assert res.exit_code == 0, res.output
172}
173
174fn test_module_resolution_is_independent_of_working_directory() {
175 workspace := setup_module_resolution_workdir_fixture()
176 defer {
177 os.rmdir_all(workspace) or {}
178 }
179 res_root := vrun_ok_in_dir(workspace, 'run', 'app')
180 assert res_root.trim_space() == 'Hello 16!'
181
182 res_app := vrun_ok_in_dir(os.join_path(workspace, 'app'), 'run', '.')
183 assert res_app.trim_space() == 'Hello 16!'
184}
185
186fn test_running_project_from_its_own_vmod_with_parent_vmod_works_issue_26828() {
187 root := os.join_path(os.vtmp_dir(), 'v_issue_26828_${os.getpid()}')
188 os.rmdir_all(root) or {}
189 defer {
190 os.rmdir_all(root) or {}
191 }
192 project_root := os.join_path(root, 'outer')
193 module_root := os.join_path(project_root, 'cli004')
194 os.mkdir_all(os.join_path(module_root, 'sub'))!
195 os.write_file(os.join_path(project_root, 'v.mod'), "Module {\n\tname: 'outer'\n}\n")!
196 os.write_file(os.join_path(module_root, 'v.mod'), "Module {\n\tname: 'cli004'\n}\n")!
197 os.write_file(os.join_path(module_root, 'cli004.v'),
198 'module main\n\nimport sub\n\nfn main() {\n\tsub.greetings()\n}\n')!
199 os.write_file(os.join_path(module_root, 'sub', 'hey.v'),
200 "module sub\n\npub fn greetings() {\n\tprintln('greetings from sub')\n}\n")!
201
202 res := vrun_ok_in_dir(module_root, 'crun', '.')
203 assert res.trim_space() == 'greetings from sub'
204}
205
206fn test_custom_print_should_compile_with_no_builtin() {
207 source_path := os.join_path(os.vtmp_dir(), 'custom_print_no_builtin_${os.getpid()}.v')
208 output_path := os.join_path(os.vtmp_dir(), 'custom_print_no_builtin_${os.getpid()}.c')
209 source := [
210 '@[markused]',
211 'pub fn error() {',
212 "\tprint(c'\\n')",
213 '}',
214 '',
215 'pub fn print(fmt voidptr, ...) {}',
216 ].join_lines()
217 os.write_file(source_path, source)!
218 defer {
219 os.rm(source_path) or {}
220 os.rm(output_path) or {}
221 }
222 _ = vrun_ok('-o ${os.quoted_path(output_path)} -no-builtin', source_path)
223 assert os.exists(output_path)
224}
225
226fn test_generic_recursive_self_method_call_should_compile() {
227 source_path := os.join_path(os.vtmp_dir(),
228 'generic_recursive_self_method_call_${os.getpid()}.v')
229 output_path := os.join_path(os.vtmp_dir(), 'generic_recursive_self_method_call_${os.getpid()}')
230 mut expected_output_path := output_path
231 $if windows {
232 expected_output_path += '.exe'
233 }
234 source := [
235 'struct Decoder {}',
236 '',
237 'struct StructTypePointer[T] {',
238 'mut:',
239 '\tval &T',
240 '}',
241 '',
242 'pub fn decode[T](val string) !T {',
243 '\tmut decoder := Decoder{}',
244 '',
245 '\tmut result := T{}',
246 '\tdecoder.decode_value(mut result)!',
247 '\treturn result',
248 '}',
249 '',
250 'fn (mut decoder Decoder) decode_value[T](mut val T) ! {',
251 '\t\$if T.indirections != 0 {',
252 '\t\tunsafe {',
253 '\t\t\t*val = 2',
254 '\t\t}',
255 '\t} \$else \$if T is \$struct {',
256 '\t\tdecode_value(mut val.val)!',
257 '\t}',
258 '}',
259 '',
260 'fn main() {',
261 "\tassert *decode[StructTypePointer[int]]('2')!.val == 2",
262 '}',
263 ].join_lines()
264 write_file(source_path, source)
265 defer {
266 os.rm(source_path) or {}
267 os.rm(output_path) or {}
268 os.rm(expected_output_path) or {}
269 }
270 _ = vrun_ok('-o ${os.quoted_path(output_path)}', source_path)
271 assert os.exists(expected_output_path)
272}
273
274fn test_sync_waitgroup_should_check_for_windows() {
275 source_path := os.join_path(os.vtmp_dir(), 'sync_waitgroup_issue_14468_${os.getpid()}.v')
276 source := [
277 'module main',
278 '',
279 'import sync',
280 '',
281 'fn main() {',
282 '\tmut wg := sync.new_waitgroup()',
283 '\twg.add(1)',
284 '\twg.done()',
285 '\twg.wait()',
286 '}',
287 ].join_lines()
288 write_file(source_path, source)
289 defer {
290 os.rm(source_path) or {}
291 }
292 _ = vrun_ok('-os windows -check', source_path)
293}
294
295fn test_usecache_build_module_sumtype_uses_canonical_type_id_helper() {
296 root := os.join_path(os.vtmp_dir(), 'usecache_sumtype_cross_module_${os.getpid()}')
297 cache_dir := os.join_path(root, '.cache')
298 vtmp_dir := os.join_path(root, '.vtmp')
299 os.rmdir_all(root) or {}
300 defer {
301 os.rmdir_all(root) or {}
302 }
303 os.mkdir_all(os.join_path(root, 'payload'))!
304 os.mkdir_all(os.join_path(root, 'maker'))!
305 os.mkdir_all(vtmp_dir)!
306 write_file(os.join_path(root, 'v.mod'), "Module {\n\tname: 'ucsmt'\n}\n")
307 write_file(os.join_path(root, 'payload', 'payload.v'),
308 'module payload\n\npub struct Foo {\n\tpub:\n\t\tn int\n}\n\npub struct Bar {\n\tpub:\n\t\ts string\n}\n\npub type Value = Foo | Bar\n')
309 write_file(os.join_path(root, 'maker', 'maker.v'),
310 'module maker\n\nimport payload\n\npub fn make() payload.Value {\n\treturn payload.Value(payload.Foo{n: 42})\n}\n')
311 old_vcache := os.getenv_opt('VCACHE') or { '' }
312 old_vtmp := os.getenv_opt('VTMP') or { '' }
313 os.setenv('VCACHE', cache_dir, true)
314 os.setenv('VTMP', vtmp_dir, true)
315 defer {
316 if old_vcache.len == 0 {
317 os.unsetenv('VCACHE')
318 } else {
319 os.setenv('VCACHE', old_vcache, true)
320 }
321 if old_vtmp.len == 0 {
322 os.unsetenv('VTMP')
323 } else {
324 os.setenv('VTMP', old_vtmp, true)
325 }
326 }
327 mut p := os.new_process(@VEXE)
328 p.set_work_folder(root)
329 p.set_args(['-keepc', 'build-module', 'maker'])
330 p.set_redirect_stdio()
331 p.wait()
332 stdout := p.stdout_slurp()
333 stderr := p.stderr_slurp()
334 exit_code := p.code
335 p.close()
336 assert exit_code == 0, '${stdout}${stderr}'
337 generated_c_path := os.join_path(vtmp_dir, 'maker.tmp.c')
338 assert os.exists(generated_c_path)
339 generated_c := os.read_file(generated_c_path)!
340 assert generated_c.contains('payload__Foo_to_sumtype_payload__Value(payload__Foo* x, bool is_mut)')
341 assert generated_c.contains('._typ = _v_type_idx_payload__Foo()')
342}
343
344fn test_readline_raw_mode_methods_should_check_for_windows() {
345 source_path := os.join_path(os.vtmp_dir(), 'readline_raw_mode_issue_24686_${os.getpid()}.v')
346 source := [
347 'module main',
348 '',
349 'import readline',
350 '',
351 'fn main() {',
352 '\tmut r := readline.Readline{}',
353 '\tr.enable_raw_mode()',
354 '\tr.disable_raw_mode()',
355 '\tr.enable_raw_mode_nosig()',
356 '\tprintln(r.read_char()!)',
357 '\tr.disable_raw_mode()',
358 '}',
359 ].join_lines()
360 write_file(source_path, source)
361 defer {
362 os.rm(source_path) or {}
363 }
364 _ = vrun_ok('-os windows -check', source_path)
365}
366