v / vlib / os
Raw file | 1014 loc (932 sloc) | 26.79 KB | Latest commit hash 3aeb6179b
1import os
2import time
3
4const (
5 // tfolder will contain all the temporary files/subfolders made by
6 // the different tests. It would be removed in testsuite_end(), so
7 // individual os tests do not need to clean up after themselves.
8 tfolder = os.join_path(os.vtmp_dir(), 'v', 'tests', 'os_test')
9)
10
11// os.args has to be *already initialized* with the program's argc/argv at this point
12// thus it can be used for other consts too:
13const args_at_start = os.args.clone()
14
15fn testsuite_begin() {
16 eprintln('testsuite_begin, tfolder = ${tfolder}')
17 os.rmdir_all(tfolder) or {}
18 assert !os.is_dir(tfolder)
19 os.mkdir_all(tfolder) or { panic(err) }
20 os.chdir(tfolder) or {}
21 assert os.is_dir(tfolder)
22 // println('args_at_start: $args_at_start')
23 assert args_at_start.len > 0
24 assert args_at_start == os.args
25}
26
27fn testsuite_end() {
28 os.chdir(os.wd_at_startup) or {}
29 os.rmdir_all(tfolder) or {}
30 // assert !os.is_dir(tfolder)
31 // eprintln('testsuite_end , tfolder = $tfolder removed.')
32}
33
34fn test_open_file() {
35 filename := './test1.txt'
36 hello := 'hello world!'
37 os.open_file(filename, 'r+', 0o666) or {
38 assert err.msg() == 'No such file or directory'
39 os.File{}
40 }
41 mut file := os.open_file(filename, 'w+', 0o666) or { panic(err) }
42 file.write_string(hello) or { panic(err) }
43 file.close()
44 assert u64(hello.len) == os.file_size(filename)
45 read_hello := os.read_file(filename) or { panic('error reading file ${filename}') }
46 assert hello == read_hello
47 os.rm(filename) or { panic(err) }
48}
49
50fn test_read_file_from_virtual_filesystem() {
51 $if linux {
52 mounts := os.read_file('/proc/mounts')!
53
54 // it is not empty, contains some mounting such as root filesystem: /dev/x / ext4 rw 0 0
55 assert mounts.len > 20
56 assert mounts.contains('/')
57 assert mounts.contains(' ')
58 }
59}
60
61fn test_read_binary_from_virtual_filesystem() {
62 $if linux {
63 mounts_raw := os.read_bytes('/proc/mounts')!
64 mounts := mounts_raw.bytestr()
65
66 // it is not empty, contains some mounting such as root filesystem: /dev/x / ext4 rw 0 0
67 assert mounts.len > 20
68 assert mounts.contains('/')
69 assert mounts.contains(' ')
70 }
71}
72
73fn test_open_file_binary() {
74 filename := './test1.dat'
75 hello := 'hello \n world!'
76 os.open_file(filename, 'r+', 0o666) or {
77 assert err.msg() == 'No such file or directory'
78 os.File{}
79 }
80 mut file := os.open_file(filename, 'wb+', 0o666) or { panic(err) }
81 bytes := hello.bytes()
82 unsafe { file.write_ptr(bytes.data, bytes.len) }
83 file.close()
84 assert u64(hello.len) == os.file_size(filename)
85 read_hello := os.read_bytes(filename) or { panic('error reading file ${filename}') }
86 assert bytes == read_hello
87 os.rm(filename) or { panic(err) }
88}
89
90// fn test_file_get_line() {
91// filename := './fgetline.txt'
92// os.write_file(filename, 'line 1\nline 2')
93// mut f := os.open_file(filename, 'r', 0) or {
94// assert false
95// return
96// }
97// line1 := f.get_line() or {
98// ''
99// }
100// line2 := f.get_line() or {
101// ''
102// }
103// f.close()
104// //
105// eprintln('line1: $line1 $line1.bytes()')
106// eprintln('line2: $line2 $line2.bytes()')
107// assert line1 == 'line 1\n'
108// assert line2 == 'line 2'
109// }
110
111fn create_file(fpath string) ! {
112 mut f := os.create(fpath)!
113 f.close()
114}
115
116fn create_and_write_to_file(fpath string, content string) ! {
117 mut f := os.create(fpath)!
118 f.write_string(content)!
119 f.close()
120}
121
122fn test_create_file() {
123 filename := './test1.txt'
124 hello := 'hello world!'
125 create_and_write_to_file(filename, hello)!
126 assert u64(hello.len) == os.file_size(filename)
127 os.rm(filename) or { panic(err) }
128}
129
130fn test_is_file() {
131 // Setup
132 work_dir := os.join_path_single(tfolder, 'is_file_test')
133 os.mkdir_all(work_dir) or { panic(err) }
134 tfile := os.join_path_single(work_dir, 'tmp_file')
135 // Test things that shouldn't be a file
136 assert os.is_file(work_dir) == false
137 assert os.is_file('non-existent_file.tmp') == false
138 // Test file
139 tfile_content := 'temporary file'
140 os.write_file(tfile, tfile_content) or { panic(err) }
141 assert os.is_file(tfile)
142 // Test dir symlinks
143 $if windows {
144 assert true
145 } $else {
146 dsymlink := os.join_path_single(work_dir, 'dir_symlink')
147 os.symlink(work_dir, dsymlink) or { panic(err) }
148 assert os.is_file(dsymlink) == false
149 }
150 // Test file symlinks
151 $if windows {
152 assert true
153 } $else {
154 fsymlink := os.join_path_single(work_dir, 'file_symlink')
155 os.symlink(tfile, fsymlink) or { panic(err) }
156 assert os.is_file(fsymlink)
157 }
158}
159
160fn test_write_and_read_string_to_file() {
161 filename := './test1.txt'
162 hello := 'hello world!'
163 os.write_file(filename, hello) or { panic(err) }
164 assert u64(hello.len) == os.file_size(filename)
165 read_hello := os.read_file(filename) or { panic('error reading file ${filename}') }
166 assert hello == read_hello
167 os.rm(filename) or { panic(err) }
168}
169
170// test_write_and_read_bytes checks for regressions made in the functions
171// read_bytes, read_bytes_at and write_bytes.
172
173fn test_write_and_read_bytes() {
174 file_name := './byte_reader_writer.tst'
175 payload := [u8(`I`), `D`, `D`, `Q`, `D`]
176 mut file_write := os.create(os.real_path(file_name)) or {
177 eprintln('failed to create file ${file_name}')
178 return
179 }
180 // We use the standard write_bytes function to write the payload and
181 // compare the length of the array with the file size (have to match).
182 unsafe { file_write.write_ptr(payload.data, 5) }
183 file_write.close()
184 assert u64(payload.len) == os.file_size(file_name)
185 mut file_read := os.open(os.real_path(file_name)) or {
186 eprintln('failed to open file ${file_name}')
187 return
188 }
189 // We only need to test read_bytes because this function calls
190 // read_bytes_at with second parameter zeroed (size, 0).
191 rbytes := file_read.read_bytes(5)
192 // eprintln('rbytes: $rbytes')
193 // eprintln('payload: $payload')
194 assert rbytes == payload
195 // check that trying to read data from EOF doesn't error and returns 0
196 mut a := []u8{len: 5}
197 nread := file_read.read_bytes_into(5, mut a) or {
198 n := if err is os.Eof {
199 int(0)
200 } else {
201 eprintln(err)
202 int(-1)
203 }
204 n
205 }
206 assert nread == 0
207 file_read.close()
208 // We finally delete the test file.
209 os.rm(file_name) or { panic(err) }
210}
211
212fn test_ls() {
213 if x := os.ls('') {
214 assert false
215 } else {
216 assert true
217 }
218 if x := os.ls('.') {
219 assert x.len > 0
220 } else {
221 assert false
222 }
223}
224
225fn create_tree() ! {
226 os.mkdir_all('myfolder/f1/f2/f3')!
227 os.mkdir_all('myfolder/a1/a2/a3', mode: 0o700)!
228 f3 := os.real_path('myfolder/f1/f2/f3')
229 assert os.is_dir(f3)
230 create_file('myfolder/f1/f2/f3/a.txt')!
231 create_file('myfolder/f1/f2/f3/b.txt')!
232 create_file('myfolder/f1/f2/f3/c.txt')!
233 create_file('myfolder/f1/f2/f3/d.md')!
234 create_file('myfolder/f1/0.txt')!
235 create_file('myfolder/another.md')!
236 create_file('myfolder/a1/a2/a3/x.txt')!
237 create_file('myfolder/a1/a2/a3/y.txt')!
238 create_file('myfolder/a1/a2/a3/z.txt')!
239 create_file('myfolder/a1/1.txt')!
240 create_file('myfolder/xyz.ini')!
241}
242
243fn remove_tree() {
244 os.rmdir_all('myfolder') or {}
245}
246
247fn normalise_paths(paths []string) []string {
248 mut res := paths.map(it.replace(os.path_separator, '/'))
249 res.sort()
250 return res
251}
252
253fn test_walk_ext() {
254 create_tree()!
255 defer {
256 remove_tree()
257 }
258 all := os.walk_ext('.', '')
259 assert all.len > 10
260 top := normalise_paths(os.walk_ext('myfolder', '.txt'))
261 assert top == [
262 'myfolder/a1/1.txt',
263 'myfolder/a1/a2/a3/x.txt',
264 'myfolder/a1/a2/a3/y.txt',
265 'myfolder/a1/a2/a3/z.txt',
266 'myfolder/f1/0.txt',
267 'myfolder/f1/f2/f3/a.txt',
268 'myfolder/f1/f2/f3/b.txt',
269 'myfolder/f1/f2/f3/c.txt',
270 ]
271 subfolder_txts := normalise_paths(os.walk_ext('myfolder/a1/a2', '.txt'))
272 assert subfolder_txts == [
273 'myfolder/a1/a2/a3/x.txt',
274 'myfolder/a1/a2/a3/y.txt',
275 'myfolder/a1/a2/a3/z.txt',
276 ]
277 mut mds := normalise_paths(os.walk_ext('myfolder', '.md'))
278 assert mds == ['myfolder/another.md', 'myfolder/f1/f2/f3/d.md']
279}
280
281fn test_walk_with_context() {
282 create_tree()!
283 defer {
284 remove_tree()
285 }
286 mut res := []string{}
287 os.walk_with_context('myfolder', &res, fn (mut res []string, fpath string) {
288 res << fpath
289 })
290 res = normalise_paths(res)
291 assert 'myfolder/f1/f2/f3/b.txt' in res
292 assert 'myfolder/another.md' in res
293}
294
295fn test_create_and_delete_folder() {
296 folder := './test1'
297 os.mkdir(folder) or { panic(err) }
298 assert os.is_dir(folder)
299 folder_contents := os.ls(folder) or { panic(err) }
300 assert folder_contents.len == 0
301 os.rmdir(folder) or { panic(err) }
302 folder_exists := os.is_dir(folder)
303 assert folder_exists == false
304}
305
306fn walk_callback(file string) {
307 if file == '.' || file == '..' {
308 return
309 }
310 assert file == 'test_walk' + os.path_separator + 'test1'
311}
312
313fn test_walk() {
314 folder := 'test_walk'
315 os.mkdir(folder) or { panic(err) }
316 file1 := folder + os.path_separator + 'test1'
317 os.write_file(file1, 'test-1') or { panic(err) }
318 os.walk(folder, walk_callback)
319 os.rm(file1) or { panic(err) }
320 os.rmdir(folder) or { panic(err) }
321}
322
323fn test_cp() {
324 old_file_name := 'cp_example.txt'
325 new_file_name := 'cp_new_example.txt'
326 os.write_file(old_file_name, 'Test data 1 2 3, V is awesome #$%^[]!~⭐') or { panic(err) }
327 os.cp(old_file_name, new_file_name) or { panic('${err}') }
328 old_file := os.read_file(old_file_name) or { panic(err) }
329 new_file := os.read_file(new_file_name) or { panic(err) }
330 assert old_file == new_file
331 os.rm(old_file_name) or { panic(err) }
332 os.rm(new_file_name) or { panic(err) }
333}
334
335fn test_mv() {
336 work_dir := os.join_path_single(tfolder, 'mv_test')
337 os.mkdir_all(work_dir) or { panic(err) }
338 // Setup test files
339 tfile1 := os.join_path_single(work_dir, 'file')
340 tfile2 := os.join_path_single(work_dir, 'file.test')
341 tfile3 := os.join_path_single(work_dir, 'file.3')
342 tfile_content := 'temporary file'
343 os.write_file(tfile1, tfile_content) or { panic(err) }
344 os.write_file(tfile2, tfile_content) or { panic(err) }
345 // Setup test dirs
346 tdir1 := os.join_path_single(work_dir, 'dir')
347 tdir2 := os.join_path_single(work_dir, 'dir2')
348 tdir3 := os.join_path_single(work_dir, 'dir3')
349 os.mkdir(tdir1) or { panic(err) }
350 os.mkdir(tdir2) or { panic(err) }
351 // Move file with no extension to dir
352 os.mv(tfile1, tdir1) or { panic(err) }
353 mut expected := os.join_path_single(tdir1, 'file')
354 assert os.exists(expected)
355 assert !os.is_dir(expected)
356 // Move dir with contents to other dir
357 os.mv(tdir1, tdir2) or { panic(err) }
358 expected = os.join_path_single(tdir2, 'dir')
359 assert os.exists(expected)
360 assert os.is_dir(expected)
361 expected = os.join_path(tdir2, 'dir', 'file')
362 assert os.exists(expected)
363 assert !os.is_dir(expected)
364 // Move dir with contents to other dir (by renaming)
365 os.mv(os.join_path_single(tdir2, 'dir'), tdir3) or { panic(err) }
366 expected = tdir3
367 assert os.exists(expected)
368 assert os.is_dir(expected)
369 assert os.is_dir_empty(tdir2)
370 // Move file with extension to dir
371 os.mv(tfile2, tdir2) or { panic(err) }
372 expected = os.join_path_single(tdir2, 'file.test')
373 assert os.exists(expected)
374 assert !os.is_dir(expected)
375 // Move file to dir (by renaming)
376 os.mv(os.join_path_single(tdir2, 'file.test'), tfile3) or { panic(err) }
377 expected = tfile3
378 assert os.exists(expected)
379 assert !os.is_dir(expected)
380}
381
382fn test_is_dir_empty() {
383 // Test that is_dir_empty returns true on
384 // non-existent directories ***as stated in it's doc string***
385 assert os.is_dir_empty('dir that does not exist at all')
386}
387
388fn test_cp_all() {
389 // fileX -> dir/fileX
390 // Note: clean up of the files happens inside the cleanup_leftovers function
391 os.write_file('ex1.txt', 'wow!') or { panic(err) }
392 os.mkdir('ex') or { panic(err) }
393 os.cp_all('ex1.txt', 'ex', false) or { panic(err) }
394 old := os.read_file('ex1.txt') or { panic(err) }
395 new := os.read_file('ex/ex1.txt') or { panic(err) }
396 assert old == new
397 os.mkdir('ex/ex2') or { panic(err) }
398 os.write_file('ex2.txt', 'great!') or { panic(err) }
399 os.cp_all('ex2.txt', 'ex/ex2', false) or { panic(err) }
400 old2 := os.read_file('ex2.txt') or { panic(err) }
401 new2 := os.read_file('ex/ex2/ex2.txt') or { panic(err) }
402 assert old2 == new2
403 // recurring on dir -> local dir
404 os.cp_all('ex', './', true) or { panic(err) }
405 // regression test for executive runs with overwrite := true
406 os.cp_all('ex', './', true) or { panic(err) }
407 os.cp_all('ex', 'nonexisting', true) or { panic(err) }
408 assert os.exists(os.join_path_single('nonexisting', 'ex1.txt'))
409}
410
411fn test_realpath_of_empty_string_works() {
412 assert os.real_path('') == ''
413}
414
415fn test_realpath_non_existing() {
416 non_existing_path := 'sdyfuisd_non_existing_file'
417 rpath := os.real_path(non_existing_path)
418 $if windows {
419 // on windows, the workdir is prepended, so the result is absolute:
420 assert rpath.len > non_existing_path.len
421 }
422 $if !windows {
423 // on unix, the workdir is NOT prepended for now, so the result remains the same.
424 // TODO: the windows behaviour seems saner, think about normalising the unix case to do the same.
425 assert os.real_path(non_existing_path) == non_existing_path
426 }
427}
428
429fn test_realpath_existing() {
430 existing_file_name := 'existing_file.txt'
431 existing_file := os.join_path_single(tfolder, existing_file_name)
432 os.rm(existing_file) or {}
433 os.write_file(existing_file, 'abc') or {}
434 assert os.exists(existing_file)
435 rpath := os.real_path(existing_file)
436 assert os.is_abs_path(rpath)
437 assert rpath.ends_with(existing_file_name)
438 os.rm(existing_file) or {}
439}
440
441fn test_realpath_removes_dots() {
442 examples_folder := os.join_path(@VEXEROOT, 'vlib', 'v', '..', '..', 'cmd', '.', '..',
443 'examples')
444 real_path_of_examples_folder := os.real_path(examples_folder)
445 assert real_path_of_examples_folder.len < examples_folder.len
446 assert !real_path_of_examples_folder.contains('..')
447}
448
449fn test_realpath_absolutizes_existing_relative_paths() {
450 old_wd := os.getwd()
451 defer {
452 os.chdir(old_wd) or { panic(err) }
453 }
454 os.chdir(@VEXEROOT) or { panic(err) }
455 examples_folder := os.join_path('vlib', 'v', '..', '..', 'cmd', '.', '..', 'examples')
456 real_path_of_examples_folder := os.real_path(examples_folder)
457 assert os.is_abs_path(real_path_of_examples_folder)
458}
459
460// TODO: think much more about whether this is desirable:
461
462fn test_realpath_does_not_absolutize_non_existing_relative_paths() {
463 relative_path := os.join_path('one', 'nonexisting_folder', '..', 'something')
464 $if !windows {
465 assert os.real_path(relative_path).contains('..')
466 assert os.real_path(relative_path) == relative_path
467 }
468}
469
470fn test_realpath_absolutepath_symlink() {
471 file_name := 'tolink_file.txt'
472 symlink_name := 'symlink.txt'
473 create_file(file_name)!
474 os.symlink(file_name, symlink_name)!
475 rpath := os.real_path(symlink_name)
476 println(rpath)
477 assert os.is_abs_path(rpath)
478 assert rpath.ends_with(file_name)
479 os.rm(symlink_name) or {}
480 os.rm(file_name) or {}
481}
482
483fn test_make_symlink_check_is_link_and_remove_symlink() {
484 folder := 'tfolder'
485 symlink := 'tsymlink'
486 // windows creates a directory symlink, so delete it with rmdir()
487 $if windows {
488 os.rmdir(symlink) or {}
489 } $else {
490 os.rm(symlink) or {}
491 }
492 os.rmdir(folder) or {}
493 os.mkdir(folder) or { panic(err) }
494 folder_contents := os.ls(folder) or { panic(err) }
495 assert folder_contents.len == 0
496 os.symlink(folder, symlink) or { panic(err) }
497 assert os.is_link(symlink)
498 $if windows {
499 os.rmdir(symlink) or { panic(err) }
500 } $else {
501 os.rm(symlink) or { panic(err) }
502 }
503 os.rmdir(folder) or { panic(err) }
504 folder_exists := os.is_dir(folder)
505 assert folder_exists == false
506 symlink_exists := os.is_link(symlink)
507 assert symlink_exists == false
508}
509
510fn test_make_symlink_check_is_link_and_remove_symlink_with_file() {
511 file := 'tfile'
512 symlink := 'tsymlink'
513 os.rm(symlink) or {}
514 os.rm(file) or {}
515 create_file(file)!
516 os.symlink(file, symlink) or { panic(err) }
517 assert os.is_link(symlink)
518 os.rm(symlink) or { panic(err) }
519 os.rm(file) or { panic(err) }
520 symlink_exists := os.is_link(symlink)
521 assert symlink_exists == false
522}
523
524fn test_make_hardlink_check_is_link_and_remove_hardlink_with_file() {
525 file := 'tfile'
526 symlink := 'tsymlink'
527 os.rm(symlink) or {}
528 os.rm(file) or {}
529 create_file(file)!
530 os.link(file, symlink) or { panic(err) }
531 assert os.exists(symlink)
532 os.rm(symlink) or { panic(err) }
533 os.rm(file) or { panic(err) }
534 symlink_exists := os.is_link(symlink)
535 assert symlink_exists == false
536}
537
538// fn test_fork() {
539// pid := os.fork()
540// if pid == 0 {
541// println('Child')
542// }
543// else {
544// println('Parent')
545// }
546// }
547// fn test_wait() {
548// pid := os.fork()
549// if pid == 0 {
550// println('Child')
551// exit(0)
552// }
553// else {
554// cpid := os.wait()
555// println('Parent')
556// println(cpid)
557// }
558// }
559
560fn test_symlink() {
561 os.mkdir('symlink') or { panic(err) }
562 os.symlink('symlink', 'symlink2') or { panic(err) }
563 assert os.exists('symlink2')
564 // cleanup
565 os.rmdir('symlink') or { panic(err) }
566 $if windows {
567 os.rmdir('symlink2') or { panic(err) }
568 } $else {
569 os.rm('symlink2') or { panic(err) }
570 }
571}
572
573fn test_is_executable_writable_readable() {
574 file_name := 'rwxfile.exe'
575 create_file(file_name)!
576 $if !windows {
577 os.chmod(file_name, 0o600) or {} // mark as readable && writable, but NOT executable
578 assert os.is_writable(file_name)
579 assert os.is_readable(file_name)
580 assert !os.is_executable(file_name)
581 os.chmod(file_name, 0o700) or {} // mark as executable too
582 assert os.is_executable(file_name)
583 } $else {
584 assert os.is_writable(file_name)
585 assert os.is_readable(file_name)
586 assert os.is_executable(file_name)
587 }
588 // We finally delete the test file.
589 os.rm(file_name) or { panic(err) }
590}
591
592fn test_file_ext() {
593 assert os.file_ext('file.v') == '.v'
594 assert os.file_ext('file.js.v') == '.v'
595 assert os.file_ext('file.ext1.ext2.ext3') == '.ext3'
596 assert os.file_ext('.ignore_me.v') == '.v'
597 assert os.file_ext('file') == ''
598 assert os.file_ext('.git') == ''
599 assert os.file_ext('file.') == ''
600 assert os.file_ext('.') == ''
601 assert os.file_ext('..') == ''
602 assert os.file_ext('file...') == ''
603 assert os.file_ext('.file.') == ''
604 assert os.file_ext('..file..') == ''
605 assert os.file_ext('./.git') == ''
606 assert os.file_ext('./.git/') == ''
607 assert os.file_ext('\\.git') == ''
608 assert os.file_ext('\\.git\\') == ''
609}
610
611fn test_join() {
612 $if windows {
613 assert os.join_path('v', 'vlib', 'os') == 'v\\vlib\\os'
614 } $else {
615 assert os.join_path('v', 'vlib', 'os') == 'v/vlib/os'
616 assert os.join_path('/foo/bar', './file.txt') == '/foo/bar/file.txt'
617 }
618}
619
620fn test_rmdir_all() {
621 mut dirs := ['some/dir', 'some/.hidden/directory']
622 $if windows {
623 for mut d in dirs {
624 d = d.replace('/', '\\')
625 }
626 }
627 for d in dirs {
628 os.mkdir_all(d) or { panic(err) }
629 assert os.is_dir(d)
630 }
631 os.rmdir_all('some') or { assert false }
632 assert !os.exists('some')
633}
634
635fn test_dir() {
636 $if windows {
637 assert os.dir('C:\\a\\b\\c') == 'C:\\a\\b'
638 assert os.dir('C:\\a\\b\\') == 'C:\\a\\b'
639 assert os.dir('C:/a/b/c') == 'C:\\a\\b'
640 assert os.dir('C:/a/b/') == 'C:\\a\\b'
641 } $else {
642 assert os.dir('/') == '/'
643 assert os.dir('/abc') == '/'
644 assert os.dir('/var/tmp/foo') == '/var/tmp'
645 assert os.dir('/var/tmp/') == '/var/tmp'
646 assert os.dir('C:\\a\\b\\c') == 'C:/a/b'
647 assert os.dir('C:\\a\\b\\') == 'C:/a/b'
648 }
649 assert os.dir('os') == '.'
650}
651
652fn test_base() {
653 $if windows {
654 assert os.base('v\\vlib\\os') == 'os'
655 assert os.base('v\\vlib\\os\\') == 'os'
656 assert os.base('v/vlib/os') == 'os'
657 assert os.base('v/vlib/os/') == 'os'
658 } $else {
659 assert os.base('v/vlib/os') == 'os'
660 assert os.base('v/vlib/os/') == 'os'
661 assert os.base('v\\vlib\\os') == 'os'
662 assert os.base('v\\vlib\\os\\') == 'os'
663 }
664 assert os.base('filename') == 'filename'
665}
666
667fn test_file_name() {
668 $if windows {
669 assert os.file_name('v\\vlib\\os\\os.v') == 'os.v'
670 assert os.file_name('v\\vlib\\os\\') == ''
671 assert os.file_name('v\\vlib\\os') == 'os'
672 } $else {
673 assert os.file_name('v/vlib/os/os.v') == 'os.v'
674 assert os.file_name('v/vlib/os/') == ''
675 assert os.file_name('v/vlib/os') == 'os'
676 }
677 assert os.file_name('filename') == 'filename'
678}
679
680fn test_uname() {
681 u := os.uname()
682 assert u.sysname.len > 0
683 assert u.nodename.len > 0
684 assert u.release.len > 0
685 assert u.version.len > 0
686 assert u.machine.len > 0
687}
688
689// tests for write_file_array and read_file_array[T]:
690const maxn = 3
691
692struct IntPoint {
693 x int
694 y int
695}
696
697fn test_write_file_array_bytes() {
698 fpath := './abytes.bin'
699 mut arr := []u8{len: maxn}
700 for i in 0 .. maxn {
701 arr[i] = 65 + u8(i)
702 }
703 os.write_file_array(fpath, arr) or { panic(err) }
704 rarr := os.read_bytes(fpath) or { panic(err) }
705 assert arr == rarr
706 // eprintln(arr.str())
707 // eprintln(rarr.str())
708}
709
710fn test_write_file_array_structs() {
711 fpath := './astructs.bin'
712 mut arr := []IntPoint{len: maxn}
713 for i in 0 .. maxn {
714 arr[i] = IntPoint{65 + i, 65 + i + 10}
715 }
716 os.write_file_array(fpath, arr) or { panic(err) }
717 rarr := os.read_file_array[IntPoint](fpath)
718 assert rarr == arr
719 assert rarr.len == maxn
720 // eprintln( rarr.str().replace('\n', ' ').replace('},', '},\n'))
721}
722
723fn test_stdout_capture() {
724 /*
725 mut cmd := os.Command{
726 path:'cat'
727 redirect_stdout: true
728}
729cmd.start()
730for !cmd.eof {
731 line := cmd.read_line()
732 println('line="$line"')
733}
734cmd.close()
735 */
736}
737
738fn test_posix_set_bit() {
739 $if windows {
740 assert true
741 } $else {
742 fpath := 'permtest'
743 create_file(fpath)!
744 os.chmod(fpath, 0o0777) or { panic(err) }
745 c_fpath := &char(fpath.str)
746 mut s := C.stat{}
747 unsafe {
748 C.stat(c_fpath, &s)
749 }
750 // Take the permissions part of the mode
751 mut mode := u32(s.st_mode) & 0o0777
752 assert mode == 0o0777
753 // `chmod u-r`
754 os.posix_set_permission_bit(fpath, os.s_irusr, false)
755 unsafe {
756 C.stat(c_fpath, &s)
757 }
758 mode = u32(s.st_mode) & 0o0777
759 assert mode == 0o0377
760 // `chmod u+r`
761 os.posix_set_permission_bit(fpath, os.s_irusr, true)
762 unsafe {
763 C.stat(c_fpath, &s)
764 }
765 mode = u32(s.st_mode) & 0o0777
766 assert mode == 0o0777
767 // Note: setting the sticky bit is platform dependend
768 // `chmod -s -g -t`
769 os.posix_set_permission_bit(fpath, os.s_isuid, false)
770 os.posix_set_permission_bit(fpath, os.s_isgid, false)
771 os.posix_set_permission_bit(fpath, os.s_isvtx, false)
772 unsafe {
773 C.stat(c_fpath, &s)
774 }
775 mode = u32(s.st_mode) & 0o0777
776 assert mode == 0o0777
777 // `chmod g-w o-w`
778 os.posix_set_permission_bit(fpath, os.s_iwgrp, false)
779 os.posix_set_permission_bit(fpath, os.s_iwoth, false)
780 unsafe {
781 C.stat(c_fpath, &s)
782 }
783 mode = u32(s.st_mode) & 0o7777
784 assert mode == 0o0755
785 os.rm(fpath) or {}
786 }
787}
788
789fn test_exists_in_system_path() {
790 assert os.exists_in_system_path('') == false
791 $if windows {
792 assert os.exists_in_system_path('cmd.exe')
793 return
794 }
795 assert os.exists_in_system_path('ls')
796}
797
798fn test_truncate() {
799 filename := './test_trunc.txt'
800 hello := 'hello world!'
801 mut f := os.create(filename)!
802 f.write_string(hello)!
803 f.close()
804 assert u64(hello.len) == os.file_size(filename)
805 newlen := u64(40000)
806 os.truncate(filename, newlen) or { panic(err) }
807 assert newlen == os.file_size(filename)
808 os.rm(filename) or { panic(err) }
809}
810
811fn test_hostname() {
812 hostname := os.hostname() or { '' }
813 assert hostname.len > 2
814}
815
816// fn test_loginname() {
817// loginname := os.loginname() or { '' }
818// assert loginname.len > 2
819//}
820
821fn test_glob() {
822 os.mkdir('test_dir') or { panic(err) }
823 for i in 0 .. 4 {
824 if i == 3 {
825 create_file('test_dir/test0_another')!
826 create_file('test_dir/test')!
827 } else {
828 create_file('test_dir/test' + i.str())!
829 }
830 }
831 files := os.glob('test_dir/t*') or { panic(err) }
832 assert files.len == 5
833 assert os.base(files[0]) == 'test'
834
835 for i in 0 .. 3 {
836 os.rm('test_dir/test' + i.str()) or { panic(err) }
837 }
838 os.rm('test_dir/test0_another') or { panic(err) }
839 os.rm('test_dir/test') or { panic(err) }
840 os.rmdir_all('test_dir') or { panic(err) }
841}
842
843fn test_utime() {
844 filename := './test_utime.txt'
845 hello := 'hello world!'
846 mut f := os.create(filename) or { panic(err) }
847 defer {
848 f.close()
849 os.rm(filename) or { panic(err) }
850 }
851 f.write_string(hello) or { panic(err) }
852 atime := time.now().add_days(2).unix_time()
853 mtime := time.now().add_days(4).unix_time()
854 os.utime(filename, int(atime), int(mtime)) or { panic(err) }
855 assert os.file_last_mod_unix(filename) == mtime
856}
857
858fn test_execute() {
859 print0script := os.join_path_single(tfolder, 'print0.v')
860 // The output of the next command contains a 0 byte in the middle.
861 // Nevertheless, the execute function *should* return a string that
862 // contains it.
863 os.write_file(print0script, 'C.printf(c"start%cMIDDLE%cfinish\nxx", 0, 0)\n')!
864 defer {
865 os.rm(print0script) or {}
866 }
867 result := os.execute('${os.quoted_path(@VEXE)} run ${os.quoted_path(print0script)}')
868 hexresult := result.output.bytes().hex()
869 // println('exit_code: $result.exit_code')
870 // println('output: |$result.output|')
871 // println('output.len: $result.output.len')
872 // println('output hexresult: $hexresult')
873 assert result.exit_code == 0
874 assert hexresult.starts_with('7374617274004d4944444c450066696e697368')
875 assert hexresult.ends_with('0a7878')
876}
877
878fn test_execute_with_stderr_redirection() {
879 result := os.execute('${os.quoted_path(@VEXE)} wrong_command')
880 assert result.exit_code == 1
881 assert result.output.contains('unknown command `wrong_command`')
882
883 stderr_path := os.join_path_single(tfolder, 'stderr.txt')
884 result2 := os.execute('${os.quoted_path(@VEXE)} wrong_command 2> ${os.quoted_path(stderr_path)}')
885 assert result2.exit_code == 1
886 assert result2.output == ''
887 assert os.exists(stderr_path)
888}
889
890fn test_command() {
891 if os.user_os() == 'windows' {
892 eprintln('>>> os.Command is not implemented fully on Windows yet')
893 return
894 }
895 mut cmd := os.Command{
896 path: 'ls'
897 }
898
899 cmd.start() or { panic(err) }
900 for !cmd.eof {
901 cmd.read_line()
902 }
903
904 cmd.close() or { panic(err) }
905 // dump( cmd )
906 assert cmd.exit_code == 0
907
908 // This will return a non 0 code
909 mut cmd_to_fail := os.Command{
910 path: 'ls -M'
911 }
912
913 cmd_to_fail.start() or { panic(err) }
914 for !cmd_to_fail.eof {
915 cmd_to_fail.read_line()
916 }
917
918 cmd_to_fail.close() or { panic(err) }
919 // dump( cmd_to_fail )
920 assert cmd_to_fail.exit_code != 0 // 2 on linux, 1 on macos
921}
922
923fn test_reading_from_proc_cpuinfo() {
924 // This test is only for plain linux systems (they have a /proc virtual filesystem).
925 $if android {
926 assert true
927 return
928 }
929 $if !linux {
930 assert true
931 return
932 }
933 info := os.read_file('/proc/cpuinfo')!
934 assert info.len > 0
935 assert info.contains('processor')
936 assert info.ends_with('\n\n')
937
938 info_bytes := os.read_bytes('/proc/cpuinfo')!
939 assert info_bytes.len > 0
940 assert info.len == info_bytes.len
941}
942
943fn test_reading_from_empty_file() {
944 empty_file := os.join_path_single(tfolder, 'empty_file.txt')
945 os.rm(empty_file) or {}
946 assert !os.exists(empty_file)
947 os.write_file(empty_file, '')!
948 assert os.exists(empty_file)
949 content := os.read_file(empty_file)!
950 assert content.len == 0
951 content_bytes := os.read_bytes(empty_file)!
952 assert content_bytes.len == 0
953 os.rm(empty_file)!
954}
955
956fn move_across_partitions_using_function(f fn (src string, dst string) !) ! {
957 bindfs := os.find_abs_path_of_executable('bindfs') or {
958 eprintln('skipping test_mv_by_cp, because bindfs was not present')
959 return
960 }
961 // eprintln('>> $bindfs')
962 pfolder := os.join_path(tfolder, 'parent')
963 cfolder := os.join_path(pfolder, 'child')
964 mfolder := os.join_path(pfolder, 'mountpoint')
965 cdeepfolder := os.join_path(cfolder, 'deep', 'folder')
966 os.mkdir_all(mfolder)!
967 os.mkdir_all(cfolder)!
968 os.mkdir_all(cdeepfolder)!
969 //
970 original_path := os.join_path(pfolder, 'original.txt')
971 target_path := os.join_path(cdeepfolder, 'target.txt')
972 os.write_file(original_path, 'text')!
973 os.write_file(os.join_path(cdeepfolder, 'x.txt'), 'some text')!
974 // os.system('tree $pfolder')
975 /*
976 /tmp/v_1000/v/tests/os_test/parent
977 ├── child
978 │   └── deep
979 │   └── folder
980 │   └── x.txt
981 ├── mountpoint
982 └── original.txt
983 */
984 os.system('${bindfs} --no-allow-other ${cfolder} ${mfolder}')
985 defer {
986 os.system('sync; umount ${mfolder}')
987 }
988 // os.system('tree $pfolder')
989 /*
990 /tmp/v_1000/v/tests/os_test/parent
991 ├── child
992 │   └── deep
993 │   └── folder
994 │   └── x.txt
995 ├── mountpoint
996 │ └── deep
997 │ └── folder
998 │ └── x.txt
999 └── original.txt
1000 */
1001
1002 f(original_path, target_path)!
1003
1004 assert os.exists(target_path)
1005 assert !os.exists(original_path)
1006}
1007
1008fn test_mv_by_cp_across_partitions() {
1009 move_across_partitions_using_function(os.mv_by_cp)!
1010}
1011
1012fn test_mv_across_partitions() {
1013 move_across_partitions_using_function(os.mv)!
1014}