From e7dbabf6681e4e6bcae33398e939c2c9c3cdc879 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 9 Feb 2026 15:50:21 +0100 Subject: core:os -> core:os/old && core:os/os2 -> core:os --- tests/core/encoding/hxa/test_core_hxa.odin | 2 +- tests/core/flags/test_core_flags.odin | 22 +- tests/core/io/test_core_io.odin | 14 +- tests/core/nbio/fs.odin | 8 +- tests/core/nbio/nbio.odin | 12 +- tests/core/normal.odin | 2 +- tests/core/os/dir.odin | 116 ++++++ tests/core/os/file.odin | 33 ++ tests/core/os/old/os.odin | 63 +++ tests/core/os/os.odin | 63 --- tests/core/os/os2/dir.odin | 116 ------ tests/core/os/os2/file.odin | 33 -- tests/core/os/os2/path.odin | 562 -------------------------- tests/core/os/os2/process.odin | 26 -- tests/core/os/path.odin | 562 ++++++++++++++++++++++++++ tests/core/os/process.odin | 26 ++ tests/core/sys/kqueue/structs.odin | 6 +- tests/documentation/documentation_tester.odin | 4 +- 18 files changed, 835 insertions(+), 835 deletions(-) create mode 100644 tests/core/os/dir.odin create mode 100644 tests/core/os/file.odin create mode 100644 tests/core/os/old/os.odin delete mode 100644 tests/core/os/os.odin delete mode 100644 tests/core/os/os2/dir.odin delete mode 100644 tests/core/os/os2/file.odin delete mode 100644 tests/core/os/os2/path.odin delete mode 100644 tests/core/os/os2/process.odin create mode 100644 tests/core/os/path.odin create mode 100644 tests/core/os/process.odin (limited to 'tests') diff --git a/tests/core/encoding/hxa/test_core_hxa.odin b/tests/core/encoding/hxa/test_core_hxa.odin index 17b3ca619..a4fee030c 100644 --- a/tests/core/encoding/hxa/test_core_hxa.odin +++ b/tests/core/encoding/hxa/test_core_hxa.odin @@ -6,7 +6,7 @@ import "core:testing" TEAPOT_PATH :: ODIN_ROOT + "tests/core/assets/HXA/teapot.hxa" -import os "core:os/os2" +import "core:os" @test test_read :: proc(t: ^testing.T) { diff --git a/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin index 1aee7f69c..834f6b630 100644 --- a/tests/core/flags/test_core_flags.odin +++ b/tests/core/flags/test_core_flags.odin @@ -1,16 +1,16 @@ package test_core_flags -import "base:runtime" -import "core:bytes" -import "core:flags" -import "core:fmt" -@require import "core:log" -import "core:math" -@require import "core:net" -import os "core:os/os2" -import "core:strings" -import "core:testing" -import "core:time/datetime" +import "base:runtime" +import "core:bytes" +import "core:flags" +import "core:fmt" +@(require) import "core:log" +import "core:math" +@(require) import "core:net" +import "core:os" +import "core:strings" +import "core:testing" +import "core:time/datetime" Custom_Data :: struct { a: int, diff --git a/tests/core/io/test_core_io.odin b/tests/core/io/test_core_io.odin index eb4d79317..301e7bb94 100644 --- a/tests/core/io/test_core_io.odin +++ b/tests/core/io/test_core_io.odin @@ -1,12 +1,12 @@ package test_core_io -import "core:bufio" -import "core:bytes" -import "core:io" -import "core:log" -import os "core:os/os2" -import "core:strings" -import "core:testing" +import "core:bufio" +import "core:bytes" +import "core:io" +import "core:log" +import "core:os" +import "core:strings" +import "core:testing" Passed_Tests :: distinct io.Stream_Mode_Set diff --git a/tests/core/nbio/fs.odin b/tests/core/nbio/fs.odin index 6e079f96e..1b10c03c9 100644 --- a/tests/core/nbio/fs.odin +++ b/tests/core/nbio/fs.odin @@ -1,9 +1,9 @@ package tests_nbio -import "core:nbio" -import "core:testing" -import "core:time" -import os "core:os/os2" +import "core:nbio" +import "core:testing" +import "core:time" +import "core:os" @(test) close_invalid_handle :: proc(t: ^testing.T) { diff --git a/tests/core/nbio/nbio.odin b/tests/core/nbio/nbio.odin index 2f454f55b..6c3fd0e8c 100644 --- a/tests/core/nbio/nbio.odin +++ b/tests/core/nbio/nbio.odin @@ -1,11 +1,11 @@ package tests_nbio -import "core:log" -import "core:nbio" -import "core:testing" -import "core:thread" -import "core:time" -import os "core:os/os2" +import "core:log" +import "core:nbio" +import "core:testing" +import "core:thread" +import "core:time" +import "core:os" ev :: testing.expect_value e :: testing.expect diff --git a/tests/core/normal.odin b/tests/core/normal.odin index 6b31b9d56..4708ed700 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -37,7 +37,7 @@ download_assets :: proc "contextless" () { @(require) import "net" @(require) import "odin" @(require) import "os" -@(require) import "os/os2" +@(require) import "os/old" @(require) import "reflect" @(require) import "runtime" @(require) import "slice" diff --git a/tests/core/os/dir.odin b/tests/core/os/dir.odin new file mode 100644 index 000000000..464abed98 --- /dev/null +++ b/tests/core/os/dir.odin @@ -0,0 +1,116 @@ +package tests_core_os + +import "core:os" +import "core:log" +import "core:slice" +import "core:testing" +import "core:strings" + +@(test) +test_read_dir :: proc(t: ^testing.T) { + path, err_join := os.join_path({#directory, "dir"}, context.allocator) + defer delete(path) + + fis, err_read := os.read_all_directory_by_path(path, context.allocator) + defer os.file_info_slice_delete(fis, context.allocator) + + slice.sort_by_key(fis, proc(fi: os.File_Info) -> string { return fi.name }) + + if err_read == .Unsupported { + log.warn("core:os directory functionality is unsupported, skipping test") + return + } + + testing.expect_value(t, err_join, nil) + testing.expect_value(t, err_read, nil) + testing.expect_value(t, len(fis), 2) + + testing.expect_value(t, fis[0].name, "b.txt") + testing.expect_value(t, fis[0].type, os.File_Type.Regular) + + testing.expect_value(t, fis[1].name, "sub") + testing.expect_value(t, fis[1].type, os.File_Type.Directory) +} + +@(test) +test_walker :: proc(t: ^testing.T) { + path, err := os.join_path({#directory, "dir"}, context.allocator) + defer delete(path) + testing.expect_value(t, err, nil) + + w := os.walker_create(path) + defer os.walker_destroy(&w) + + test_walker_internal(t, &w) +} + +@(test) +test_walker_file :: proc(t: ^testing.T) { + path, err_join := os.join_path({#directory, "dir"}, context.allocator) + defer delete(path) + testing.expect_value(t, err_join, nil) + + f, err_open := os.open(path) + testing.expect_value(t, err_open, nil) + defer os.close(f) + + w := os.walker_create(f) + defer os.walker_destroy(&w) + + test_walker_internal(t, &w) +} + +test_walker_internal :: proc(t: ^testing.T, w: ^os.Walker) { + Seen :: struct { + type: os.File_Type, + path: string, + } + + joined_1, err_joined_1 := os.join_path({"dir", "b.txt"}, context.allocator) + joined_2, err_joined_2 := os.join_path({"dir", "sub"}, context.allocator) + joined_3, err_joined_3 := os.join_path({"dir", "sub", ".gitkeep"}, context.allocator) + + testing.expect_value(t, err_joined_1, nil) + testing.expect_value(t, err_joined_2, nil) + testing.expect_value(t, err_joined_3, nil) + + expected := [?]Seen{ + {.Regular, joined_1}, + {.Directory, joined_2}, + {.Regular, joined_3}, + } + + seen: [dynamic]Seen + defer delete(seen) + + for info in os.walker_walk(w) { + + errpath, err := os.walker_error(w) + testing.expectf(t, err == nil, "walker error for %q: %v", errpath, err) + + append(&seen, Seen{ + info.type, + strings.clone(info.fullpath), + }) + } + + if _, err := os.walker_error(w); err == .Unsupported { + log.warn("core:os directory functionality is unsupported, skipping test") + return + } + + testing.expect_value(t, len(seen), len(expected)) + + for expectation in expected { + found: bool + for entry in seen { + if strings.has_suffix(entry.path, expectation.path) { + found = true + testing.expect_value(t, entry.type, expectation.type) + delete(entry.path) + } + } + testing.expectf(t, found, "%q not found in %v", expectation, seen) + delete(expectation.path) + } +} diff --git a/tests/core/os/file.odin b/tests/core/os/file.odin new file mode 100644 index 000000000..aed57c26c --- /dev/null +++ b/tests/core/os/file.odin @@ -0,0 +1,33 @@ +package tests_core_os + +import "core:os" +import "core:testing" + +@(test) +test_clone :: proc(t: ^testing.T) { + joined, err := os.join_path({#directory, "file.odin"}, context.temp_allocator) + testing.expect_value(t, err, nil) + f: ^os.File + f, err = os.open(joined) + testing.expect_value(t, err, nil) + testing.expect(t, f != nil) + + clone: ^os.File + clone, err = os.clone(f) + testing.expect_value(t, err, nil) + testing.expect(t, clone != nil) + + testing.expect_value(t, os.name(clone), os.name(f)) + testing.expect(t, os.fd(clone) != os.fd(f)) + + os.close(f) + + buf: [128]byte + n: int + n, err = os.read(clone, buf[:]) + testing.expect_value(t, err, nil) + testing.expect(t, n > 13) + testing.expect_value(t, string(buf[:13]), "package tests") + + os.close(clone) +} diff --git a/tests/core/os/old/os.odin b/tests/core/os/old/os.odin new file mode 100644 index 000000000..9925cf708 --- /dev/null +++ b/tests/core/os/old/os.odin @@ -0,0 +1,63 @@ +package test_core_os_old + +import "core:c/libc" +import win32 "core:sys/windows" +import os "core:os/old" +import "core:slice" +import "core:testing" +import "core:log" + +_ :: libc +_ :: win32 + +@(test) +read_dir :: proc(t: ^testing.T) { + when ODIN_OS == .Windows { + link := win32.utf8_to_wstring(#directory + "dir/alink.txt") + target := win32.utf8_to_wstring(#directory + "dir/a.txt") + sym_err := win32.CreateSymbolicLinkW(link, target, win32.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) + + if !sym_err { + log.infof("Unable to create symlink, skipping test. Error: %v", win32.GetLastError()) + return + } + } else { + sym_err := libc.system("ln -s " + #directory + "dir/a.txt " + #directory + "dir/alink.txt") + if sym_err != 0 { + log.infof("Unable to create symlink, skipping test. Error: %v", sym_err) + return + } + } + defer os.remove(#directory + "dir/alink.txt") + + fd, err := os.open(#directory + "/dir") + testing.expect_value(t, err, nil) + defer { + testing.expect_value(t, os.close(fd), nil) + } + + dir, err2 := os.read_dir(fd, -1) + testing.expect_value(t, err2, nil) + defer os.file_info_slice_delete(dir) + + slice.sort_by_key(dir, proc(fi: os.File_Info) -> string { return fi.name }) + + testing.expect_value(t, len(dir), 3) + + if len(dir) > 0 { + testing.expect_value(t, dir[0].name, "alink.txt") + testing.expect(t, !dir[0].is_dir, "is a directory") + when ODIN_OS == .Windows { + testing.expect(t, dir[0].mode & os.File_Mode_Sym_Link != 0, "not a symlink") + } else { + testing.expect(t, os.S_ISLNK(auto_cast dir[0].mode), "not a symlink") + } + } + if len(dir) > 1 { + testing.expect_value(t, dir[1].name, "b.txt") + } + if len(dir) > 2 { + testing.expect_value(t, dir[2].name, "sub") + testing.expect(t, dir[2].is_dir, "is not a directory") + } +} diff --git a/tests/core/os/os.odin b/tests/core/os/os.odin deleted file mode 100644 index 1510bad31..000000000 --- a/tests/core/os/os.odin +++ /dev/null @@ -1,63 +0,0 @@ -package test_core_os - -import "core:c/libc" -import win32 "core:sys/windows" -import "core:os" -import "core:slice" -import "core:testing" -import "core:log" - -_ :: libc -_ :: win32 - -@(test) -read_dir :: proc(t: ^testing.T) { - when ODIN_OS == .Windows { - link := win32.utf8_to_wstring(#directory + "dir/alink.txt") - target := win32.utf8_to_wstring(#directory + "dir/a.txt") - sym_err := win32.CreateSymbolicLinkW(link, target, win32.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) - - if !sym_err { - log.infof("Unable to create symlink, skipping test. Error: %v", win32.GetLastError()) - return - } - } else { - sym_err := libc.system("ln -s " + #directory + "dir/a.txt " + #directory + "dir/alink.txt") - if sym_err != 0 { - log.infof("Unable to create symlink, skipping test. Error: %v", sym_err) - return - } - } - defer os.remove(#directory + "dir/alink.txt") - - fd, err := os.open(#directory + "/dir") - testing.expect_value(t, err, nil) - defer { - testing.expect_value(t, os.close(fd), nil) - } - - dir, err2 := os.read_dir(fd, -1) - testing.expect_value(t, err2, nil) - defer os.file_info_slice_delete(dir) - - slice.sort_by_key(dir, proc(fi: os.File_Info) -> string { return fi.name }) - - testing.expect_value(t, len(dir), 3) - - if len(dir) > 0 { - testing.expect_value(t, dir[0].name, "alink.txt") - testing.expect(t, !dir[0].is_dir, "is a directory") - when ODIN_OS == .Windows { - testing.expect(t, dir[0].mode & os.File_Mode_Sym_Link != 0, "not a symlink") - } else { - testing.expect(t, os.S_ISLNK(auto_cast dir[0].mode), "not a symlink") - } - } - if len(dir) > 1 { - testing.expect_value(t, dir[1].name, "b.txt") - } - if len(dir) > 2 { - testing.expect_value(t, dir[2].name, "sub") - testing.expect(t, dir[2].is_dir, "is not a directory") - } -} diff --git a/tests/core/os/os2/dir.odin b/tests/core/os/os2/dir.odin deleted file mode 100644 index 8ef333219..000000000 --- a/tests/core/os/os2/dir.odin +++ /dev/null @@ -1,116 +0,0 @@ -package tests_core_os_os2 - -import os "core:os/os2" -import "core:log" -import "core:slice" -import "core:testing" -import "core:strings" - -@(test) -test_read_dir :: proc(t: ^testing.T) { - path, err_join := os.join_path({#directory, "../dir"}, context.allocator) - defer delete(path) - - fis, err_read := os.read_all_directory_by_path(path, context.allocator) - defer os.file_info_slice_delete(fis, context.allocator) - - slice.sort_by_key(fis, proc(fi: os.File_Info) -> string { return fi.name }) - - if err_read == .Unsupported { - log.warn("os2 directory functionality is unsupported, skipping test") - return - } - - testing.expect_value(t, err_join, nil) - testing.expect_value(t, err_read, nil) - testing.expect_value(t, len(fis), 2) - - testing.expect_value(t, fis[0].name, "b.txt") - testing.expect_value(t, fis[0].type, os.File_Type.Regular) - - testing.expect_value(t, fis[1].name, "sub") - testing.expect_value(t, fis[1].type, os.File_Type.Directory) -} - -@(test) -test_walker :: proc(t: ^testing.T) { - path, err := os.join_path({#directory, "../dir"}, context.allocator) - defer delete(path) - testing.expect_value(t, err, nil) - - w := os.walker_create(path) - defer os.walker_destroy(&w) - - test_walker_internal(t, &w) -} - -@(test) -test_walker_file :: proc(t: ^testing.T) { - path, err_join := os.join_path({#directory, "../dir"}, context.allocator) - defer delete(path) - testing.expect_value(t, err_join, nil) - - f, err_open := os.open(path) - testing.expect_value(t, err_open, nil) - defer os.close(f) - - w := os.walker_create(f) - defer os.walker_destroy(&w) - - test_walker_internal(t, &w) -} - -test_walker_internal :: proc(t: ^testing.T, w: ^os.Walker) { - Seen :: struct { - type: os.File_Type, - path: string, - } - - joined_1, err_joined_1 := os.join_path({"dir", "b.txt"}, context.allocator) - joined_2, err_joined_2 := os.join_path({"dir", "sub"}, context.allocator) - joined_3, err_joined_3 := os.join_path({"dir", "sub", ".gitkeep"}, context.allocator) - - testing.expect_value(t, err_joined_1, nil) - testing.expect_value(t, err_joined_2, nil) - testing.expect_value(t, err_joined_3, nil) - - expected := [?]Seen{ - {.Regular, joined_1}, - {.Directory, joined_2}, - {.Regular, joined_3}, - } - - seen: [dynamic]Seen - defer delete(seen) - - for info in os.walker_walk(w) { - - errpath, err := os.walker_error(w) - testing.expectf(t, err == nil, "walker error for %q: %v", errpath, err) - - append(&seen, Seen{ - info.type, - strings.clone(info.fullpath), - }) - } - - if _, err := os.walker_error(w); err == .Unsupported { - log.warn("os2 directory functionality is unsupported, skipping test") - return - } - - testing.expect_value(t, len(seen), len(expected)) - - for expectation in expected { - found: bool - for entry in seen { - if strings.has_suffix(entry.path, expectation.path) { - found = true - testing.expect_value(t, entry.type, expectation.type) - delete(entry.path) - } - } - testing.expectf(t, found, "%q not found in %v", expectation, seen) - delete(expectation.path) - } -} diff --git a/tests/core/os/os2/file.odin b/tests/core/os/os2/file.odin deleted file mode 100644 index 0152a2008..000000000 --- a/tests/core/os/os2/file.odin +++ /dev/null @@ -1,33 +0,0 @@ -package tests_core_os_os2 - -import os "core:os/os2" -import "core:testing" - -@(test) -test_clone :: proc(t: ^testing.T) { - joined, err := os.join_path({#directory, "file.odin"}, context.temp_allocator) - testing.expect_value(t, err, nil) - f: ^os.File - f, err = os.open(joined) - testing.expect_value(t, err, nil) - testing.expect(t, f != nil) - - clone: ^os.File - clone, err = os.clone(f) - testing.expect_value(t, err, nil) - testing.expect(t, clone != nil) - - testing.expect_value(t, os.name(clone), os.name(f)) - testing.expect(t, os.fd(clone) != os.fd(f)) - - os.close(f) - - buf: [128]byte - n: int - n, err = os.read(clone, buf[:]) - testing.expect_value(t, err, nil) - testing.expect(t, n > 13) - testing.expect_value(t, string(buf[:13]), "package tests") - - os.close(clone) -} diff --git a/tests/core/os/os2/path.odin b/tests/core/os/os2/path.odin deleted file mode 100644 index 868023c86..000000000 --- a/tests/core/os/os2/path.odin +++ /dev/null @@ -1,562 +0,0 @@ -package tests_core_os_os2 - -import "core:fmt" -import os "core:os/os2" -import "core:log" -import "core:testing" -import "core:slice" -import "core:strings" - -@(test) -test_executable :: proc(t: ^testing.T) { - path, err := os.get_executable_path(context.allocator) - defer delete(path) - - log.infof("executable path: %q", path) - - // NOTE: some sanity checks that should always be the case, at least in the CI. - - testing.expect_value(t, err, nil) - testing.expect(t, len(path) > 0) - testing.expect(t, os.is_absolute_path(path)) - _, filename := os.split_path(os.args[0]) - testing.expectf(t, strings.contains(path, filename), "expected the executable path to contain the base of os.args[0] which is %q", filename) -} - -posix_to_dos_path :: proc(path: string) -> string { - if len(path) == 0 { - return path - } - path := path - path, _ = strings.replace_all(path, `/`, `\`, context.temp_allocator) - if path[0] == '\\' { - path = strings.concatenate({"C:", path}, context.temp_allocator) - } - return path -} - -@(test) -test_clean_path :: proc(t: ^testing.T) { - Test_Case :: struct{ - path: string, - expected: string, - } - - when ODIN_OS == .Windows { - test_cases := [?]Test_Case { - {`W:/odin\examples\demo/demo.odin`, `W:\odin\examples\demo\demo.odin`}, - {`\\server\share\path\file.ext`, `\\server\share\path\file.ext`}, - {`//server\share/path\file.ext`, `\\server\share\path\file.ext`}, - {`/\192.168.0.10\share/path\file.ext`, `\\192.168.0.10\share\path\file.ext`}, - {`\\?\C:/Users/Foo/path\file.ext`, `\\?\C:\Users\Foo\path\file.ext`}, - {`\\?\\localhost\share\file.ext`, `\\?\\localhost\share\file.ext`}, - {`//?\/192.168.0.10\share\file.ext`, `\\?\\192.168.0.10\share\file.ext`}, - {`\\.\PhysicalDrive3`, `\\.\PhysicalDrive3`}, - {`/\./PhysicalDrive3`, `\\.\PhysicalDrive3`}, - {`C:\a\..\..`, `C:\`}, - {`C:\a\..`, `C:\`}, - {`C:\あ/a/..`, `C:\あ`}, - {`C:\あ/a/../あ`, `C:\あ\あ`}, - } - } else { - test_cases := [?]Test_Case { - {`../../foo/../../`, `../../..`}, - {`../../foo/..`, `../..`}, - {`../../foo`, `../../foo`}, - {`../..`, `../..`}, - {`.././foo`, `../foo`}, - {`..`, `..`}, - {`.`, `.`}, - {`.foo`, `.foo`}, - {`/../../foo/../../`, `/`}, - {`/../`, `/`}, - {`/..`, `/`}, - {`/`, `/`}, - {`//home/foo/bar/../../`, `/home`}, - {`/a/../..`, `/`}, - {`/a/../`, `/`}, - {`/a/あ`, `/a/あ`}, - {`/a/あ/..`, `/a`}, - {`/あ/a/..`, `/あ`}, - {`/あ/a/../あ`, `/あ/あ`}, - {`/home/../`, `/`}, - {`/home/..`, `/`}, - {`/home/foo/../../usr`, `/usr`}, - {`/home/foo/../..`, `/`}, - {`/home/foo/../`, `/home`}, - {``, `.`}, - {`a/..`, `.`}, - {`a`, `a`}, - {`abc//.//../foo`, `foo`}, - {`foo`, `foo`}, - {`home/foo/bar/../../`, `home`}, - } - } - - for tc in test_cases { - joined, err := os.clean_path(tc.path, context.temp_allocator) - testing.expectf(t, joined == tc.expected && err == nil, "expected clean_path(%q) -> %q; got: %q, %v", tc.path, tc.expected, joined, err) - } -} - -@(test) -test_is_absolute_path :: proc(t: ^testing.T) { - when ODIN_OS == .Windows { - testing.expect(t, os.is_absolute_path(`C:\Windows`)) - } else { - testing.expect(t, os.is_absolute_path("/home")) - } - testing.expect(t, !os.is_absolute_path("home")) -} - -@(test) -test_get_relative_path :: proc(t: ^testing.T) { - Test_Case :: struct { - base, target: string, - expected: string, - } - - Fail_Case :: struct { - base, target: string, - } - - test_cases := [?]Test_Case { - {"", "foo", "foo"}, - {".", "foo", "foo"}, - {"/", "/", "."}, - {"/", "/home/alice/bert", "home/alice/bert"}, - {"/a", "/b", "../b"}, - {"/あ", "/あ/a", "a"}, - {"/a", "/a/あ", "あ"}, - {"/あ", "/い", "../い"}, - {"/a", "/usr", "../usr"}, - {"/home", "/", ".."}, - {"/home", "/home/alice/bert", "alice/bert"}, - {"/home/foo", "/", "../.."}, - {"/home/foo", "/home", ".."}, - {"/home/foo", "/home/alice/bert", "../alice/bert"}, - {"/home/foo", "/home/foo", "."}, - {"/home/foo", "/home/foo/bar", "bar"}, - {"/home/foo/bar", "/home", "../.."}, - {"/home/foo/bar", "/home/alice/bert", "../../alice/bert"}, - {"/home/foo/bar/bert", "/home/alice/bert", "../../../alice/bert"}, - {"/www", "/mount", "../mount"}, - {"foo", ".", ".."}, - {"foo", "bar", "../bar"}, - {"foo", "bar", "../bar"}, - {"foo", "../bar", "../../bar"}, - {"foo", "foo", "."}, - {"foo", "foo/bar", "bar"}, - {"home/foo/bar", "home/alice/bert", "../../alice/bert"}, - } - - fail_cases := [?]Fail_Case { - {"", "/home"}, - {"/home", ""}, - {"..", ""}, - } - - when ODIN_OS == .Windows { - for &tc in test_cases { - tc.base = posix_to_dos_path(tc.base) - tc.target = posix_to_dos_path(tc.target) - // Make one part all capitals to test case-insensitivity. - tc.target = strings.to_upper(tc.target, context.temp_allocator) - tc.expected = posix_to_dos_path(tc.expected) - } - for &tc in fail_cases { - tc.base = posix_to_dos_path(tc.base) - tc.target = posix_to_dos_path(tc.target) - } - } - - for tc in test_cases { - result, err := os.get_relative_path(tc.base, tc.target, context.temp_allocator) - joined, err2 := os.join_path({tc.base, result}, context.temp_allocator) - - when ODIN_OS == .Windows { - passed := strings.equal_fold(result, tc.expected) && err == nil - join_guaranteed := strings.equal_fold(joined, tc.target) && err2 == nil - } else { - passed := result == tc.expected && err == nil - join_guaranteed := joined == tc.target && err2 == nil - } - testing.expectf(t, passed, "expected get_relative_path(%q, %q) -> %q; got %q, %v", tc.base, tc.target, tc.expected, result, err) - testing.expectf(t, join_guaranteed, "join_path({{%q, %q}}) guarantee of get_relative_path(%q, %q) failed; got %q, %v instead", tc.base, result, tc.base, tc.target, joined, err2) - } - - for tc in fail_cases { - result, err := os.get_relative_path(tc.base, tc.target, context.temp_allocator) - testing.expectf(t, result == "" && err != nil, "expected get_relative_path(%q, %q) to fail, got %q, %v", tc.base, tc.target, result, err) - } -} - -@(test) -test_split_path :: proc(t: ^testing.T) { - Test_Case :: struct { - path: string, - dir, filename: string, - } - - test_cases := [?]Test_Case { - { "", "", "" }, - { "/", "/", "" }, - { "/a", "/", "a" }, - { "readme.txt", "", "readme.txt" }, - { "/readme.txt", "/", "readme.txt" }, - { "/var/readme.txt", "/var", "readme.txt" }, - { "/home/foo/bar.tar.gz", "/home/foo", "bar.tar.gz" }, - } - - when ODIN_OS == .Windows { - for &tc in test_cases { - tc.path = posix_to_dos_path(tc.path) - tc.dir = posix_to_dos_path(tc.dir) - tc.filename = posix_to_dos_path(tc.filename) - } - } - - for tc in test_cases { - dir, filename := os.split_path(tc.path) - testing.expectf(t, dir == tc.dir && filename == tc.filename, "expected split_path(%q) -> %q, %q; got: %q, %q", tc.path, tc.dir, tc.filename, dir, filename) - } -} - -@(test) -test_join_path :: proc(t: ^testing.T) { - Test_Case :: struct { - elems: []string, - expected: string, - } - - test_cases := [?]Test_Case { - { {"" }, "" }, - { {"/" }, "/" }, - { {"home" }, "home" }, - { {"home", "" }, "home" }, - { {"/home", "" }, "/home" }, - { {"", "home" }, "home" }, - { {"", "/home" }, "/home" }, - { {"", "/home", "", "foo" }, "/home/foo" }, - { {"", "home", "", "", "foo", "" }, "home/foo" }, - } - - when ODIN_OS == .Windows { - for &tc in test_cases { - for &elem in tc.elems { - elem = posix_to_dos_path(elem) - } - tc.expected = posix_to_dos_path(tc.expected) - } - } - - for tc in test_cases { - result, err := os.join_path(tc.elems, context.temp_allocator) - testing.expectf(t, result == tc.expected && err == nil, "expected join_path(%v) -> %q; got: %q, %v", tc.elems, tc.expected, result, err) - } -} - -@(test) -test_split_filename :: proc(t: ^testing.T) { - Test_Case :: struct { - filename: string, - base, ext: string, - } - - test_cases := [?]Test_Case { - {"", "", ""}, - {"a", "a", ""}, - {".", ".", ""}, - {".a", ".a", ""}, - {".foo", ".foo", ""}, - {".foo.txt", ".foo", "txt"}, - {"a.b", "a", "b"}, - {"foo", "foo", ""}, - {"readme.txt", "readme", "txt"}, - {"pkg.tar.gz", "pkg.tar", "gz"}, - // Assert API ignores directory hierarchies: - {"dir/FILE.TXT", "dir/FILE", "TXT"}, - } - - for tc in test_cases { - base, ext := os.split_filename(tc.filename) - testing.expectf(t, base == tc.base && ext == tc.ext, "expected split_filename(%q) -> %q, %q; got: %q, %q", tc.filename, tc.base, tc.ext, base, ext) - } -} - -@(test) -test_split_filename_all :: proc(t: ^testing.T) { - Test_Case :: struct { - filename: string, - base, ext: string, - } - - test_cases := [?]Test_Case { - {"", "", ""}, - {"a", "a", ""}, - {".", ".", ""}, - {".a", ".a", ""}, - {".foo", ".foo", ""}, - {".foo.txt", ".foo", "txt"}, - {"a.b", "a", "b"}, - {"foo", "foo", ""}, - {"readme.txt", "readme", "txt"}, - {"pkg.tar.gz", "pkg", "tar.gz"}, - // Assert API ignores directory hierarchies: - {"dir/FILE.TXT", "dir/FILE", "TXT"}, - } - - for tc in test_cases { - base, ext := os.split_filename_all(tc.filename) - testing.expectf(t, base == tc.base && ext == tc.ext, "expected split_filename_all(%q) -> %q, %q; got: %q, %q", tc.filename, tc.base, tc.ext, base, ext) - } -} - -@(test) -test_join_filename :: proc(t: ^testing.T) { - Test_Case :: struct { - base, ext: string, - expected: string, - } - - test_cases := [?]Test_Case { - {"", "", ""}, - {"", "foo", "foo"}, - {"foo", "", "foo"}, - {"readme", "txt", "readme.txt"}, - {"pkg.tar", "gz", "pkg.tar.gz"}, - {"pkg", "tar.gz", "pkg.tar.gz"}, - // Assert API ignores directory hierarchies: - {"dir/FILE", "TXT", "dir/FILE.TXT"}, - } - - for tc in test_cases { - result, err := os.join_filename(tc.base, tc.ext, context.temp_allocator) - testing.expectf(t, result == tc.expected && err == nil, "expected join_filename(%q, %q) -> %q; got: %q, %v", tc.base, tc.ext, tc.expected, result, err) - } -} - -Glob_Test :: struct { - pattern: string, - matches: []string, - err: os.Error, -} - -glob_tests := []Glob_Test{ - { - pattern = ODIN_ROOT + "tests/core/os/*/*.txt", - matches = { - ODIN_ROOT + "tests/core/os/dir/b.txt", - }, - err = {}, - }, - { - pattern = ODIN_ROOT + "tests/core/os/os2/*.odin", - matches = { - ODIN_ROOT + "tests/core/os/os2/dir.odin", - ODIN_ROOT + "tests/core/os/os2/file.odin", - ODIN_ROOT + "tests/core/os/os2/path.odin", - ODIN_ROOT + "tests/core/os/os2/process.odin", - }, - err = {}, - }, -} - -@(test) -test_glob :: proc(t: ^testing.T) { - compare_matches :: proc(t: ^testing.T, pattern: string, globbed, expected: []string) { - glob_fold := make([]string, len(globbed), context.temp_allocator) - expect_fold := make([]string, len(globbed), context.temp_allocator) - - for glob, i in globbed { - // If `glob` returned a path in response to a pattern, - // then `match` should consider that path a match, too, - // irrespective of `/` versus `\` presence. - no_match_msg := fmt.tprintf("Expected os.match(%q, %q) to be `true`, got `false`", pattern, glob) - match, _ := os.match(pattern, glob) - - f, _ := strings.replace_all(glob, `\`, `/`, context.temp_allocator) - glob_fold[i] = f - testing.expect(t, match, no_match_msg) - } - - for exp, i in expected { - f, _ := strings.replace_all(exp, `\`, `/`, context.temp_allocator) - expect_fold[i] = f - } - - slice.sort(glob_fold) - slice.sort(expect_fold) - - not_equal_msg := fmt.tprintf("Expected os.glob(%q) to return %v, got %v", pattern, glob_fold, expect_fold) - testing.expect(t, slice.equal(glob_fold, expect_fold), not_equal_msg) - } - - for glob in glob_tests { - globbed, err := os.glob(glob.pattern, context.allocator) - defer { - for file in globbed { - delete(file) - } - delete(globbed) - } - testing.expect_value(t, err, glob.err) - compare_matches(t, glob.pattern, globbed, glob.matches) - } -} - - -// TODO: merge this and `test_split_list` -@(test) -test_split_path_list :: proc(t: ^testing.T) { - Test_Case :: struct { - path_list: string, - expected: []string, - } - - when ODIN_OS != .Windows { - test_cases := [?]Test_Case { - {``, {}}, - {`/bin:`, {`/bin`, ``}}, - {`/usr/local/bin`, {`/usr/local/bin`}}, - {`/usr/local/bin:/usr/bin`, {`/usr/local/bin`, `/usr/bin`}}, - {`"/extra bin":/bin`, {`/extra bin`, `/bin`}}, - {`"/extra:bin":/bin`, {`/extra:bin`, `/bin`}}, - } - } else { - test_cases := [?]Test_Case { - {``, {}}, - {`C:\bin;`, {`C:\bin`, ``}}, - {`C:\usr\local\bin`, {`C:\usr\local\bin`}}, - {`C:\usr\local\bin;C:\usr\bin`, {`C:\usr\local\bin`, `C:\usr\bin`}}, - {`"C:\extra bin";C:\bin`, {`C:\extra bin`, `C:\bin`}}, - {`"C:\extra;bin";C:\bin`, {`C:\extra;bin`, `C:\bin`}}, - } - } - - for tc in test_cases { - result, err := os.split_path_list(tc.path_list, context.temp_allocator) - if testing.expectf(t, len(result) == len(tc.expected), "expected split_path_list(%q) -> %v; got %v, %v", tc.path_list, tc.expected, result, err) { - ok := true - for entry, i in result { - if entry != tc.expected[i] { - ok = false - break - } - } - testing.expectf(t, ok, "expected split_path_list(%q) -> %v; got %v, %v", tc.path_list, tc.expected, result, err) - } - } -} - -@(test) -test_split_list :: proc(t: ^testing.T) { - when ODIN_OS == .Windows { - test_split_list_windows(t) - } else { - test_split_list_unix(t) - } -} - -test_split_list_windows :: proc(t: ^testing.T) { - Datum :: struct { - i: int, - v: string, - e: [3]string, - } - @static data := []Datum{ - { 0, "C:\\Odin;C:\\Visual Studio;\"C:\\Some Other\"", - [3]string{"C:\\Odin", "C:\\Visual Studio", "C:\\Some Other"} }, // Issue #1537 - { 1, "a;;b", [3]string{"a", "", "b"} }, - { 2, "a;b;", [3]string{"a", "b", ""} }, - { 3, ";a;b", [3]string{"", "a", "b"} }, - { 4, ";;", [3]string{"", "", ""} }, - { 5, "\"a;b\"c;d;\"f\"", [3]string{"a;bc", "d", "f"} }, - { 6, "\"a;b;c\";d\";e\";f", [3]string{"a;b;c", "d;e", "f"} }, - } - - for d, i in data { - assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) - r, err := os.split_path_list(d.v, context.allocator) - testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) - defer delete_split(r) - testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", i, #procedure, d.v, len(r), len(d.e))) - if len(r) == len(d.e) { - for _, j in r { - testing.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", i, #procedure, d.v, r[j], j, d.e[j])) - } - } - } - - { - v := "" - r, err := os.split_path_list(v, context.allocator) - testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) - defer delete_split(r) - testing.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) - } - { - v := "a" - r, err := os.split_path_list(v, context.allocator) - testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) - defer delete_split(r) - testing.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) - if len(r) == 1 { - testing.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) - } - } -} - -test_split_list_unix :: proc(t: ^testing.T) { - Datum :: struct { - v: string, - e: [3]string, - } - @static data := []Datum{ - { "/opt/butler:/home/fancykillerpanda/Projects/Odin/Odin:/usr/local/sbin", - [3]string{"/opt/butler", "/home/fancykillerpanda/Projects/Odin/Odin", "/usr/local/sbin"} }, // Issue #1537 - { "a::b", [3]string{"a", "", "b"} }, - { "a:b:", [3]string{"a", "b", ""} }, - { ":a:b", [3]string{"", "a", "b"} }, - { "::", [3]string{"", "", ""} }, - { "\"a:b\"c:d:\"f\"", [3]string{"a:bc", "d", "f"} }, - { "\"a:b:c\":d\":e\":f", [3]string{"a:b:c", "d:e", "f"} }, - } - - for d in data { - r, err := os.split_path_list(d.v, context.allocator) - testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) - defer delete_split(r) - testing.expectf(t, len(r) == len(d.e), "%s len(r) %d != len(d.e) %d", d.v, len(r), len(d.e)) - if len(r) == len(d.e) { - for _, j in r { - testing.expectf(t, r[j] == d.e[j], "%v -> %v[%d] != %v", d.v, r[j], j, d.e[j]) - } - } - } - - { - v := "" - r, err := os.split_path_list(v, context.allocator) - testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) - testing.expectf(t, r == nil, "'%s' -> '%v' != nil", v, r) - } - { - v := "a" - r, err := os.split_path_list(v, context.allocator) - testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) - defer delete_split(r) - testing.expectf(t, len(r) == 1, "'%s' len(r) %d != 1", v, len(r)) - if len(r) == 1 { - testing.expectf(t, r[0] == "a", "'%v' -> %v[0] != a", v, r[0]) - } - } -} - -@(private) -delete_split :: proc(s: []string) { - for part in s { - delete(part) - } - delete(s) -} \ No newline at end of file diff --git a/tests/core/os/os2/process.odin b/tests/core/os/os2/process.odin deleted file mode 100644 index c530b4c79..000000000 --- a/tests/core/os/os2/process.odin +++ /dev/null @@ -1,26 +0,0 @@ -#+build !windows -package tests_core_os_os2 - -import os "core:os/os2" -import "core:log" -import "core:testing" - -@(test) -test_process_exec :: proc(t: ^testing.T) { - state, stdout, stderr, err := os.process_exec({ - command = {"echo", "hellope"}, - }, context.allocator) - defer delete(stdout) - defer delete(stderr) - - if err == .Unsupported { - log.warn("process_exec unsupported") - return - } - - testing.expect_value(t, state.exited, true) - testing.expect_value(t, state.success, true) - testing.expect_value(t, err, nil) - testing.expect_value(t, string(stdout), "hellope\n") - testing.expect_value(t, string(stderr), "") -} diff --git a/tests/core/os/path.odin b/tests/core/os/path.odin new file mode 100644 index 000000000..cdfaed56f --- /dev/null +++ b/tests/core/os/path.odin @@ -0,0 +1,562 @@ +package tests_core_os + +import "core:fmt" +import "core:os" +import "core:log" +import "core:testing" +import "core:slice" +import "core:strings" + +@(test) +test_executable :: proc(t: ^testing.T) { + path, err := os.get_executable_path(context.allocator) + defer delete(path) + + log.infof("executable path: %q", path) + + // NOTE: some sanity checks that should always be the case, at least in the CI. + + testing.expect_value(t, err, nil) + testing.expect(t, len(path) > 0) + testing.expect(t, os.is_absolute_path(path)) + _, filename := os.split_path(os.args[0]) + testing.expectf(t, strings.contains(path, filename), "expected the executable path to contain the base of os.args[0] which is %q", filename) +} + +posix_to_dos_path :: proc(path: string) -> string { + if len(path) == 0 { + return path + } + path := path + path, _ = strings.replace_all(path, `/`, `\`, context.temp_allocator) + if path[0] == '\\' { + path = strings.concatenate({"C:", path}, context.temp_allocator) + } + return path +} + +@(test) +test_clean_path :: proc(t: ^testing.T) { + Test_Case :: struct{ + path: string, + expected: string, + } + + when ODIN_OS == .Windows { + test_cases := [?]Test_Case { + {`W:/odin\examples\demo/demo.odin`, `W:\odin\examples\demo\demo.odin`}, + {`\\server\share\path\file.ext`, `\\server\share\path\file.ext`}, + {`//server\share/path\file.ext`, `\\server\share\path\file.ext`}, + {`/\192.168.0.10\share/path\file.ext`, `\\192.168.0.10\share\path\file.ext`}, + {`\\?\C:/Users/Foo/path\file.ext`, `\\?\C:\Users\Foo\path\file.ext`}, + {`\\?\\localhost\share\file.ext`, `\\?\\localhost\share\file.ext`}, + {`//?\/192.168.0.10\share\file.ext`, `\\?\\192.168.0.10\share\file.ext`}, + {`\\.\PhysicalDrive3`, `\\.\PhysicalDrive3`}, + {`/\./PhysicalDrive3`, `\\.\PhysicalDrive3`}, + {`C:\a\..\..`, `C:\`}, + {`C:\a\..`, `C:\`}, + {`C:\あ/a/..`, `C:\あ`}, + {`C:\あ/a/../あ`, `C:\あ\あ`}, + } + } else { + test_cases := [?]Test_Case { + {`../../foo/../../`, `../../..`}, + {`../../foo/..`, `../..`}, + {`../../foo`, `../../foo`}, + {`../..`, `../..`}, + {`.././foo`, `../foo`}, + {`..`, `..`}, + {`.`, `.`}, + {`.foo`, `.foo`}, + {`/../../foo/../../`, `/`}, + {`/../`, `/`}, + {`/..`, `/`}, + {`/`, `/`}, + {`//home/foo/bar/../../`, `/home`}, + {`/a/../..`, `/`}, + {`/a/../`, `/`}, + {`/a/あ`, `/a/あ`}, + {`/a/あ/..`, `/a`}, + {`/あ/a/..`, `/あ`}, + {`/あ/a/../あ`, `/あ/あ`}, + {`/home/../`, `/`}, + {`/home/..`, `/`}, + {`/home/foo/../../usr`, `/usr`}, + {`/home/foo/../..`, `/`}, + {`/home/foo/../`, `/home`}, + {``, `.`}, + {`a/..`, `.`}, + {`a`, `a`}, + {`abc//.//../foo`, `foo`}, + {`foo`, `foo`}, + {`home/foo/bar/../../`, `home`}, + } + } + + for tc in test_cases { + joined, err := os.clean_path(tc.path, context.temp_allocator) + testing.expectf(t, joined == tc.expected && err == nil, "expected clean_path(%q) -> %q; got: %q, %v", tc.path, tc.expected, joined, err) + } +} + +@(test) +test_is_absolute_path :: proc(t: ^testing.T) { + when ODIN_OS == .Windows { + testing.expect(t, os.is_absolute_path(`C:\Windows`)) + } else { + testing.expect(t, os.is_absolute_path("/home")) + } + testing.expect(t, !os.is_absolute_path("home")) +} + +@(test) +test_get_relative_path :: proc(t: ^testing.T) { + Test_Case :: struct { + base, target: string, + expected: string, + } + + Fail_Case :: struct { + base, target: string, + } + + test_cases := [?]Test_Case { + {"", "foo", "foo"}, + {".", "foo", "foo"}, + {"/", "/", "."}, + {"/", "/home/alice/bert", "home/alice/bert"}, + {"/a", "/b", "../b"}, + {"/あ", "/あ/a", "a"}, + {"/a", "/a/あ", "あ"}, + {"/あ", "/い", "../い"}, + {"/a", "/usr", "../usr"}, + {"/home", "/", ".."}, + {"/home", "/home/alice/bert", "alice/bert"}, + {"/home/foo", "/", "../.."}, + {"/home/foo", "/home", ".."}, + {"/home/foo", "/home/alice/bert", "../alice/bert"}, + {"/home/foo", "/home/foo", "."}, + {"/home/foo", "/home/foo/bar", "bar"}, + {"/home/foo/bar", "/home", "../.."}, + {"/home/foo/bar", "/home/alice/bert", "../../alice/bert"}, + {"/home/foo/bar/bert", "/home/alice/bert", "../../../alice/bert"}, + {"/www", "/mount", "../mount"}, + {"foo", ".", ".."}, + {"foo", "bar", "../bar"}, + {"foo", "bar", "../bar"}, + {"foo", "../bar", "../../bar"}, + {"foo", "foo", "."}, + {"foo", "foo/bar", "bar"}, + {"home/foo/bar", "home/alice/bert", "../../alice/bert"}, + } + + fail_cases := [?]Fail_Case { + {"", "/home"}, + {"/home", ""}, + {"..", ""}, + } + + when ODIN_OS == .Windows { + for &tc in test_cases { + tc.base = posix_to_dos_path(tc.base) + tc.target = posix_to_dos_path(tc.target) + // Make one part all capitals to test case-insensitivity. + tc.target = strings.to_upper(tc.target, context.temp_allocator) + tc.expected = posix_to_dos_path(tc.expected) + } + for &tc in fail_cases { + tc.base = posix_to_dos_path(tc.base) + tc.target = posix_to_dos_path(tc.target) + } + } + + for tc in test_cases { + result, err := os.get_relative_path(tc.base, tc.target, context.temp_allocator) + joined, err2 := os.join_path({tc.base, result}, context.temp_allocator) + + when ODIN_OS == .Windows { + passed := strings.equal_fold(result, tc.expected) && err == nil + join_guaranteed := strings.equal_fold(joined, tc.target) && err2 == nil + } else { + passed := result == tc.expected && err == nil + join_guaranteed := joined == tc.target && err2 == nil + } + testing.expectf(t, passed, "expected get_relative_path(%q, %q) -> %q; got %q, %v", tc.base, tc.target, tc.expected, result, err) + testing.expectf(t, join_guaranteed, "join_path({{%q, %q}}) guarantee of get_relative_path(%q, %q) failed; got %q, %v instead", tc.base, result, tc.base, tc.target, joined, err2) + } + + for tc in fail_cases { + result, err := os.get_relative_path(tc.base, tc.target, context.temp_allocator) + testing.expectf(t, result == "" && err != nil, "expected get_relative_path(%q, %q) to fail, got %q, %v", tc.base, tc.target, result, err) + } +} + +@(test) +test_split_path :: proc(t: ^testing.T) { + Test_Case :: struct { + path: string, + dir, filename: string, + } + + test_cases := [?]Test_Case { + { "", "", "" }, + { "/", "/", "" }, + { "/a", "/", "a" }, + { "readme.txt", "", "readme.txt" }, + { "/readme.txt", "/", "readme.txt" }, + { "/var/readme.txt", "/var", "readme.txt" }, + { "/home/foo/bar.tar.gz", "/home/foo", "bar.tar.gz" }, + } + + when ODIN_OS == .Windows { + for &tc in test_cases { + tc.path = posix_to_dos_path(tc.path) + tc.dir = posix_to_dos_path(tc.dir) + tc.filename = posix_to_dos_path(tc.filename) + } + } + + for tc in test_cases { + dir, filename := os.split_path(tc.path) + testing.expectf(t, dir == tc.dir && filename == tc.filename, "expected split_path(%q) -> %q, %q; got: %q, %q", tc.path, tc.dir, tc.filename, dir, filename) + } +} + +@(test) +test_join_path :: proc(t: ^testing.T) { + Test_Case :: struct { + elems: []string, + expected: string, + } + + test_cases := [?]Test_Case { + { {"" }, "" }, + { {"/" }, "/" }, + { {"home" }, "home" }, + { {"home", "" }, "home" }, + { {"/home", "" }, "/home" }, + { {"", "home" }, "home" }, + { {"", "/home" }, "/home" }, + { {"", "/home", "", "foo" }, "/home/foo" }, + { {"", "home", "", "", "foo", "" }, "home/foo" }, + } + + when ODIN_OS == .Windows { + for &tc in test_cases { + for &elem in tc.elems { + elem = posix_to_dos_path(elem) + } + tc.expected = posix_to_dos_path(tc.expected) + } + } + + for tc in test_cases { + result, err := os.join_path(tc.elems, context.temp_allocator) + testing.expectf(t, result == tc.expected && err == nil, "expected join_path(%v) -> %q; got: %q, %v", tc.elems, tc.expected, result, err) + } +} + +@(test) +test_split_filename :: proc(t: ^testing.T) { + Test_Case :: struct { + filename: string, + base, ext: string, + } + + test_cases := [?]Test_Case { + {"", "", ""}, + {"a", "a", ""}, + {".", ".", ""}, + {".a", ".a", ""}, + {".foo", ".foo", ""}, + {".foo.txt", ".foo", "txt"}, + {"a.b", "a", "b"}, + {"foo", "foo", ""}, + {"readme.txt", "readme", "txt"}, + {"pkg.tar.gz", "pkg.tar", "gz"}, + // Assert API ignores directory hierarchies: + {"dir/FILE.TXT", "dir/FILE", "TXT"}, + } + + for tc in test_cases { + base, ext := os.split_filename(tc.filename) + testing.expectf(t, base == tc.base && ext == tc.ext, "expected split_filename(%q) -> %q, %q; got: %q, %q", tc.filename, tc.base, tc.ext, base, ext) + } +} + +@(test) +test_split_filename_all :: proc(t: ^testing.T) { + Test_Case :: struct { + filename: string, + base, ext: string, + } + + test_cases := [?]Test_Case { + {"", "", ""}, + {"a", "a", ""}, + {".", ".", ""}, + {".a", ".a", ""}, + {".foo", ".foo", ""}, + {".foo.txt", ".foo", "txt"}, + {"a.b", "a", "b"}, + {"foo", "foo", ""}, + {"readme.txt", "readme", "txt"}, + {"pkg.tar.gz", "pkg", "tar.gz"}, + // Assert API ignores directory hierarchies: + {"dir/FILE.TXT", "dir/FILE", "TXT"}, + } + + for tc in test_cases { + base, ext := os.split_filename_all(tc.filename) + testing.expectf(t, base == tc.base && ext == tc.ext, "expected split_filename_all(%q) -> %q, %q; got: %q, %q", tc.filename, tc.base, tc.ext, base, ext) + } +} + +@(test) +test_join_filename :: proc(t: ^testing.T) { + Test_Case :: struct { + base, ext: string, + expected: string, + } + + test_cases := [?]Test_Case { + {"", "", ""}, + {"", "foo", "foo"}, + {"foo", "", "foo"}, + {"readme", "txt", "readme.txt"}, + {"pkg.tar", "gz", "pkg.tar.gz"}, + {"pkg", "tar.gz", "pkg.tar.gz"}, + // Assert API ignores directory hierarchies: + {"dir/FILE", "TXT", "dir/FILE.TXT"}, + } + + for tc in test_cases { + result, err := os.join_filename(tc.base, tc.ext, context.temp_allocator) + testing.expectf(t, result == tc.expected && err == nil, "expected join_filename(%q, %q) -> %q; got: %q, %v", tc.base, tc.ext, tc.expected, result, err) + } +} + +Glob_Test :: struct { + pattern: string, + matches: []string, + err: os.Error, +} + +glob_tests := []Glob_Test{ + { + pattern = ODIN_ROOT + "tests/core/os/*/*.txt", + matches = { + ODIN_ROOT + "tests/core/os/dir/b.txt", + }, + err = {}, + }, + { + pattern = ODIN_ROOT + "tests/core/os/*.odin", + matches = { + ODIN_ROOT + "tests/core/os/dir.odin", + ODIN_ROOT + "tests/core/os/file.odin", + ODIN_ROOT + "tests/core/os/path.odin", + ODIN_ROOT + "tests/core/os/process.odin", + }, + err = {}, + }, +} + +@(test) +test_glob :: proc(t: ^testing.T) { + compare_matches :: proc(t: ^testing.T, pattern: string, globbed, expected: []string) { + glob_fold := make([]string, len(globbed), context.temp_allocator) + expect_fold := make([]string, len(globbed), context.temp_allocator) + + for glob, i in globbed { + // If `glob` returned a path in response to a pattern, + // then `match` should consider that path a match, too, + // irrespective of `/` versus `\` presence. + no_match_msg := fmt.tprintf("Expected os.match(%q, %q) to be `true`, got `false`", pattern, glob) + match, _ := os.match(pattern, glob) + + f, _ := strings.replace_all(glob, `\`, `/`, context.temp_allocator) + glob_fold[i] = f + testing.expect(t, match, no_match_msg) + } + + for exp, i in expected { + f, _ := strings.replace_all(exp, `\`, `/`, context.temp_allocator) + expect_fold[i] = f + } + + slice.sort(glob_fold) + slice.sort(expect_fold) + + not_equal_msg := fmt.tprintf("Expected os.glob(%q) to return %v, got %v", pattern, glob_fold, expect_fold) + testing.expect(t, slice.equal(glob_fold, expect_fold), not_equal_msg) + } + + for glob in glob_tests { + globbed, err := os.glob(glob.pattern, context.allocator) + defer { + for file in globbed { + delete(file) + } + delete(globbed) + } + testing.expect_value(t, err, glob.err) + compare_matches(t, glob.pattern, globbed, glob.matches) + } +} + + +// TODO: merge this and `test_split_list` +@(test) +test_split_path_list :: proc(t: ^testing.T) { + Test_Case :: struct { + path_list: string, + expected: []string, + } + + when ODIN_OS != .Windows { + test_cases := [?]Test_Case { + {``, {}}, + {`/bin:`, {`/bin`, ``}}, + {`/usr/local/bin`, {`/usr/local/bin`}}, + {`/usr/local/bin:/usr/bin`, {`/usr/local/bin`, `/usr/bin`}}, + {`"/extra bin":/bin`, {`/extra bin`, `/bin`}}, + {`"/extra:bin":/bin`, {`/extra:bin`, `/bin`}}, + } + } else { + test_cases := [?]Test_Case { + {``, {}}, + {`C:\bin;`, {`C:\bin`, ``}}, + {`C:\usr\local\bin`, {`C:\usr\local\bin`}}, + {`C:\usr\local\bin;C:\usr\bin`, {`C:\usr\local\bin`, `C:\usr\bin`}}, + {`"C:\extra bin";C:\bin`, {`C:\extra bin`, `C:\bin`}}, + {`"C:\extra;bin";C:\bin`, {`C:\extra;bin`, `C:\bin`}}, + } + } + + for tc in test_cases { + result, err := os.split_path_list(tc.path_list, context.temp_allocator) + if testing.expectf(t, len(result) == len(tc.expected), "expected split_path_list(%q) -> %v; got %v, %v", tc.path_list, tc.expected, result, err) { + ok := true + for entry, i in result { + if entry != tc.expected[i] { + ok = false + break + } + } + testing.expectf(t, ok, "expected split_path_list(%q) -> %v; got %v, %v", tc.path_list, tc.expected, result, err) + } + } +} + +@(test) +test_split_list :: proc(t: ^testing.T) { + when ODIN_OS == .Windows { + test_split_list_windows(t) + } else { + test_split_list_unix(t) + } +} + +test_split_list_windows :: proc(t: ^testing.T) { + Datum :: struct { + i: int, + v: string, + e: [3]string, + } + @static data := []Datum{ + { 0, "C:\\Odin;C:\\Visual Studio;\"C:\\Some Other\"", + [3]string{"C:\\Odin", "C:\\Visual Studio", "C:\\Some Other"} }, // Issue #1537 + { 1, "a;;b", [3]string{"a", "", "b"} }, + { 2, "a;b;", [3]string{"a", "b", ""} }, + { 3, ";a;b", [3]string{"", "a", "b"} }, + { 4, ";;", [3]string{"", "", ""} }, + { 5, "\"a;b\"c;d;\"f\"", [3]string{"a;bc", "d", "f"} }, + { 6, "\"a;b;c\";d\";e\";f", [3]string{"a;b;c", "d;e", "f"} }, + } + + for d, i in data { + assert(i == d.i, fmt.tprintf("wrong data index: i %d != d.i %d\n", i, d.i)) + r, err := os.split_path_list(d.v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expect(t, len(r) == len(d.e), fmt.tprintf("i:%d %s(%s) len(r) %d != len(d.e) %d", i, #procedure, d.v, len(r), len(d.e))) + if len(r) == len(d.e) { + for _, j in r { + testing.expect(t, r[j] == d.e[j], fmt.tprintf("i:%d %s(%v) -> %v[%d] != %v", i, #procedure, d.v, r[j], j, d.e[j])) + } + } + } + + { + v := "" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expect(t, r == nil, fmt.tprintf("%s(%s) -> %v != nil", #procedure, v, r)) + } + { + v := "a" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expect(t, len(r) == 1, fmt.tprintf("%s(%s) len(r) %d != 1", #procedure, v, len(r))) + if len(r) == 1 { + testing.expect(t, r[0] == "a", fmt.tprintf("%s(%v) -> %v[0] != a", #procedure, v, r[0])) + } + } +} + +test_split_list_unix :: proc(t: ^testing.T) { + Datum :: struct { + v: string, + e: [3]string, + } + @static data := []Datum{ + { "/opt/butler:/home/fancykillerpanda/Projects/Odin/Odin:/usr/local/sbin", + [3]string{"/opt/butler", "/home/fancykillerpanda/Projects/Odin/Odin", "/usr/local/sbin"} }, // Issue #1537 + { "a::b", [3]string{"a", "", "b"} }, + { "a:b:", [3]string{"a", "b", ""} }, + { ":a:b", [3]string{"", "a", "b"} }, + { "::", [3]string{"", "", ""} }, + { "\"a:b\"c:d:\"f\"", [3]string{"a:bc", "d", "f"} }, + { "\"a:b:c\":d\":e\":f", [3]string{"a:b:c", "d:e", "f"} }, + } + + for d in data { + r, err := os.split_path_list(d.v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expectf(t, len(r) == len(d.e), "%s len(r) %d != len(d.e) %d", d.v, len(r), len(d.e)) + if len(r) == len(d.e) { + for _, j in r { + testing.expectf(t, r[j] == d.e[j], "%v -> %v[%d] != %v", d.v, r[j], j, d.e[j]) + } + } + } + + { + v := "" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + testing.expectf(t, r == nil, "'%s' -> '%v' != nil", v, r) + } + { + v := "a" + r, err := os.split_path_list(v, context.allocator) + testing.expectf(t, err == nil, "Expected err to be nil, got %v", err) + defer delete_split(r) + testing.expectf(t, len(r) == 1, "'%s' len(r) %d != 1", v, len(r)) + if len(r) == 1 { + testing.expectf(t, r[0] == "a", "'%v' -> %v[0] != a", v, r[0]) + } + } +} + +@(private) +delete_split :: proc(s: []string) { + for part in s { + delete(part) + } + delete(s) +} \ No newline at end of file diff --git a/tests/core/os/process.odin b/tests/core/os/process.odin new file mode 100644 index 000000000..adb65e95f --- /dev/null +++ b/tests/core/os/process.odin @@ -0,0 +1,26 @@ +#+build !windows +package tests_core_os + +import "core:os" +import "core:log" +import "core:testing" + +@(test) +test_process_exec :: proc(t: ^testing.T) { + state, stdout, stderr, err := os.process_exec({ + command = {"echo", "hellope"}, + }, context.allocator) + defer delete(stdout) + defer delete(stderr) + + if err == .Unsupported { + log.warn("process_exec unsupported") + return + } + + testing.expect_value(t, state.exited, true) + testing.expect_value(t, state.success, true) + testing.expect_value(t, err, nil) + testing.expect_value(t, string(stdout), "hellope\n") + testing.expect_value(t, string(stderr), "") +} diff --git a/tests/core/sys/kqueue/structs.odin b/tests/core/sys/kqueue/structs.odin index edf1fdd1e..15ec3f841 100644 --- a/tests/core/sys/kqueue/structs.odin +++ b/tests/core/sys/kqueue/structs.odin @@ -1,9 +1,9 @@ #+build darwin, freebsd, openbsd, netbsd package tests_core_sys_kqueue -import "core:strings" -import "core:testing" -import os "core:os/os2" +import "core:strings" +import "core:testing" +import "core:os" @(test) structs :: proc(t: ^testing.T) { diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin index 6694de709..be59d9b4d 100644 --- a/tests/documentation/documentation_tester.odin +++ b/tests/documentation/documentation_tester.odin @@ -1,6 +1,6 @@ package documentation_tester -import os "core:os/os2" +import "core:os" import "core:fmt" import "core:strings" import "core:odin/ast" @@ -267,7 +267,7 @@ write_test_suite :: proc(example_tests: []Example_Test) { `#+private package documentation_verification -import os "core:os/os2" +import "core:os" import "core:mem" import "core:io" import "core:fmt" -- cgit v1.2.3