mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-01 00:11:13 +00:00
262 lines
7.0 KiB
Odin
262 lines
7.0 KiB
Odin
#+build linux, darwin, freebsd, openbsd, netbsd, haiku
|
|
package tests_core_posix
|
|
|
|
import "core:log"
|
|
import "core:path/filepath"
|
|
import "core:strings"
|
|
import "core:sync"
|
|
import "core:sys/posix"
|
|
import "core:testing"
|
|
import "core:time"
|
|
|
|
@(test)
|
|
test_arpa_inet :: proc(t: ^testing.T) {
|
|
|
|
check :: proc(t: ^testing.T, $af: posix.AF, src: cstring, expect: posix.pton_result, loc := #caller_location) {
|
|
when af == .INET {
|
|
addr: posix.in_addr
|
|
dst: [posix.INET_ADDRSTRLEN]byte
|
|
} else {
|
|
addr: posix.in6_addr
|
|
dst: [posix.INET6_ADDRSTRLEN]byte
|
|
}
|
|
|
|
res := posix.inet_pton(af, src, &addr)
|
|
testing.expect_value(t, res, expect, loc)
|
|
|
|
if expect == .SUCCESS {
|
|
back := posix.inet_ntop(af, &addr, raw_data(dst[:]), len(dst))
|
|
testing.expect_value(t, back, src, loc)
|
|
|
|
when af == .INET {
|
|
back = posix.inet_ntoa(addr)
|
|
testing.expect_value(t, back, src, loc)
|
|
}
|
|
}
|
|
}
|
|
|
|
check(t, .INET, "127.0.0.1", .SUCCESS)
|
|
check(t, .INET, "blah", .INVALID)
|
|
check(t, .INET6, "::1", .SUCCESS)
|
|
check(t, .INET6, "L", .INVALID)
|
|
check(t, .UNIX, "127.0.0.1", .AFNOSUPPORT)
|
|
}
|
|
|
|
@(test)
|
|
test_dirent :: proc(t: ^testing.T) {
|
|
test := #load_directory(#directory)
|
|
test_map: map[string]struct{}
|
|
defer delete(test_map)
|
|
|
|
test_map[".."] = {}
|
|
test_map["."] = {}
|
|
|
|
for file in test {
|
|
test_map[filepath.base(file.name)] = {}
|
|
}
|
|
|
|
{
|
|
list: [^]^posix.dirent
|
|
ret := posix.scandir(#directory, &list)
|
|
testing.expectf(t, ret >= 0, "%v >= 0: %v", ret, posix.strerror(posix.errno()))
|
|
defer posix.free(list)
|
|
|
|
entries := list[:ret]
|
|
for entry in entries {
|
|
defer posix.free(entry)
|
|
|
|
when ODIN_OS == .Haiku {
|
|
stat: posix.stat_t
|
|
posix.stat(cstring(raw_data(entry.d_name[:])), &stat)
|
|
|
|
if !posix.S_ISREG(stat.st_mode) {
|
|
continue
|
|
}
|
|
} else {
|
|
if entry.d_type != .REG {
|
|
continue
|
|
}
|
|
}
|
|
|
|
name := string(cstring(raw_data(entry.d_name[:])))
|
|
testing.expectf(t, name in test_map, "scandir: %v in %v", name, test_map)
|
|
}
|
|
}
|
|
|
|
{
|
|
dir := posix.opendir(#directory)
|
|
defer posix.closedir(dir)
|
|
|
|
for {
|
|
posix.set_errno(.NONE)
|
|
entry := posix.readdir(dir)
|
|
if entry == nil {
|
|
testing.expect_value(t, posix.errno(), posix.Errno.NONE)
|
|
break
|
|
}
|
|
|
|
when ODIN_OS == .Haiku {
|
|
stat: posix.stat_t
|
|
posix.stat(cstring(raw_data(entry.d_name[:])), &stat)
|
|
|
|
if !posix.S_ISREG(stat.st_mode) {
|
|
continue
|
|
}
|
|
} else {
|
|
if entry.d_type != .REG {
|
|
continue
|
|
}
|
|
}
|
|
|
|
name := string(cstring(raw_data(entry.d_name[:])))
|
|
testing.expectf(t, name in test_map, "readdir: %v in %v", name, test_map)
|
|
}
|
|
}
|
|
}
|
|
|
|
@(test)
|
|
test_errno :: proc(t: ^testing.T) {
|
|
posix.errno(posix.Errno.ENOMEM)
|
|
testing.expect_value(t, posix.errno(), posix.Errno.ENOMEM)
|
|
|
|
res := posix.open("", {})
|
|
testing.expect_value(t, res, -1)
|
|
testing.expect_value(t, posix.errno(), posix.Errno.ENOENT)
|
|
}
|
|
|
|
@(test)
|
|
test_fcntl :: proc(t: ^testing.T) {
|
|
res := posix.open(#file, { .WRONLY, .CREAT, .EXCL })
|
|
testing.expect_value(t, res, -1)
|
|
testing.expect_value(t, posix.errno(), posix.Errno.EEXIST)
|
|
}
|
|
|
|
@(test)
|
|
test_fnmatch :: proc(t: ^testing.T) {
|
|
testing.expect_value(t, posix.fnmatch("*.odin", #file, {}), 0)
|
|
testing.expect_value(t, posix.fnmatch("*.txt", #file, {}), posix.FNM_NOMATCH)
|
|
testing.expect_value(t, posix.fnmatch("**/*.odin", #file, {}), 0)
|
|
}
|
|
|
|
@(test)
|
|
test_glob :: proc(t: ^testing.T) {
|
|
glob: posix.glob_t
|
|
res := posix.glob(#directory + ":)))))))", {}, nil, &glob)
|
|
testing.expect_value(t, res, posix.Glob_Result.NOMATCH)
|
|
posix.globfree(&glob)
|
|
}
|
|
|
|
@(test)
|
|
test_langinfo :: proc(t: ^testing.T) {
|
|
locale := posix.setlocale(.TIME, nil)
|
|
testing.expectf(t, locale == "POSIX" || locale == "C", "invalid locale for test: %v", locale)
|
|
|
|
day1 := posix.nl_langinfo(.DAY_1)
|
|
testing.expect_value(t, day1, "Sunday")
|
|
}
|
|
|
|
@(test)
|
|
test_libgen :: proc(t: ^testing.T) {
|
|
tests := [][3]cstring{
|
|
{ "usr", ".", "usr" },
|
|
{ "usr/", ".", "usr" },
|
|
{ "", ".", "." },
|
|
{ "/", "/", "/" },
|
|
{ "///", "/", "/" },
|
|
{ "/usr/", "/", "usr" },
|
|
{ "/usr/lib", "/usr", "lib" },
|
|
{ "//usr//lib//", "//usr" + ("/" when ODIN_OS == .Haiku else ""), "lib" },
|
|
{ "/home//dwc//test", "/home//dwc" + ("/" when ODIN_OS == .Haiku else ""), "test" },
|
|
}
|
|
|
|
for test in tests {
|
|
// NOTE: dir/basename can change their input so they can't be literals.
|
|
|
|
dinput := strings.clone_to_cstring(string(test[0]))
|
|
defer delete(dinput)
|
|
|
|
dir := posix.dirname(dinput)
|
|
testing.expectf(t, dir == test[1], "dirname(%q) == %q, expected %q", test[0], dir, test[1])
|
|
|
|
binput := strings.clone_to_cstring(string(test[0]))
|
|
defer delete(binput)
|
|
|
|
base := posix.basename(binput)
|
|
testing.expectf(t, base == test[2], "basename(%q) == %q, expected %q", test[0], base, test[2])
|
|
}
|
|
}
|
|
|
|
@(test)
|
|
test_locale :: proc(t: ^testing.T) {
|
|
lconv := posix.localeconv()
|
|
testing.expect(t, lconv != nil)
|
|
|
|
locale := posix.setlocale(.ALL, nil)
|
|
testing.expectf(t, locale == "POSIX" || locale == "C", "%q is not POSIX or C", locale)
|
|
}
|
|
|
|
@(test)
|
|
test_monetary :: proc(t: ^testing.T) {
|
|
when ODIN_OS == .Darwin && .Address in ODIN_SANITIZER_FLAGS {
|
|
log.warn("skipping on darwin with -sanitize:address, this fails inside macOS (also from C/clang)")
|
|
return
|
|
}
|
|
|
|
value := 123456.789
|
|
buf: [128]byte
|
|
size := posix.strfmon(raw_data(buf[:]), len(buf), "%n", value)
|
|
testing.expectf(t, int(size) != -1, "strfmon failure: %v", posix.strerror(posix.errno()))
|
|
log.debug(string(buf[:size]))
|
|
}
|
|
|
|
@(test)
|
|
test_stat :: proc(t: ^testing.T) {
|
|
stat: posix.stat_t
|
|
testing.expect_value(t, posix.stat(#file, &stat), posix.result.OK)
|
|
testing.expect(t, posix.S_ISREG(stat.st_mode))
|
|
CONTENT := #load(#file)
|
|
testing.expect_value(t, stat.st_size, posix.off_t(len(CONTENT)))
|
|
}
|
|
|
|
@(test)
|
|
test_pthreads :: proc(t: ^testing.T) {
|
|
testing.set_fail_timeout(t, 3 * time.Second)
|
|
|
|
NTHREADS :: 3
|
|
thread_ids: [NTHREADS]posix.pthread_t
|
|
|
|
@static counter: int
|
|
|
|
for &tid in thread_ids {
|
|
posix.pthread_create(&tid, nil, thread_function, nil)
|
|
}
|
|
|
|
for tid in thread_ids {
|
|
posix.pthread_join(tid, nil)
|
|
}
|
|
|
|
testing.expect_value(t, counter, NTHREADS)
|
|
|
|
thread_function :: proc "c" (_: rawptr) -> rawptr {
|
|
sync.atomic_add(&counter, 1)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
@(test)
|
|
open_permissions :: proc(t: ^testing.T) {
|
|
in_mode := posix.mode_t{.IRUSR, .IWUSR, .IROTH, .IRGRP}
|
|
fd := posix.open("test_posix_permissions.txt", {.CREAT, .RDWR}, in_mode)
|
|
testing.expectf(t, fd != -1, "failed to open: %v", posix.strerror())
|
|
|
|
defer {
|
|
ret := posix.close(fd)
|
|
testing.expectf(t, ret == .OK, "failed to close: %v", posix.strerror())
|
|
ret2 := posix.remove("test_posix_permissions.txt")
|
|
testing.expectf(t, ret2 == 0, "failed to remove: %v", posix.strerror())
|
|
}
|
|
|
|
stat: posix.stat_t
|
|
res := posix.fstat(fd, &stat)
|
|
testing.expectf(t, res == .OK, "failed to stat: %v", posix.strerror())
|
|
} |