Files
Odin/tests/core/sys/posix/structs.odin
2025-01-10 06:42:19 +01:00

131 lines
3.3 KiB
Odin

#+build linux, darwin, freebsd, openbsd, netbsd, haiku
package tests_core_posix
import "core:log"
import "core:testing"
import "core:sys/posix"
// This test tests some of the process APIs of posix while also double checking size and alignment
// of the structs we bound.
@(test)
execute_struct_checks :: proc(t: ^testing.T) {
log.debug("compiling C project")
{
switch pid := posix.fork(); pid {
case -1:
log.errorf("fork() failed: %s", posix.strerror())
case 0:
c_compiler := posix.getenv("CC")
if c_compiler == nil {
c_compiler = "clang"
}
posix.execlp(c_compiler,
c_compiler, #directory + "/structs/structs.c", "-o", #directory + "/structs/c_structs", nil)
posix.exit(69)
case:
if !wait_for(t, pid) { return }
log.debug("C code has been compiled!")
}
}
log.debug("compiling Odin project")
{
switch pid := posix.fork(); pid {
case -1:
log.errorf("fork() failed: %s", posix.strerror())
case 0:
posix.execlp(ODIN_ROOT + "/odin",
ODIN_ROOT + "/odin", "build", #directory + "/structs/structs.odin", "-out:" + #directory + "/structs/odin_structs", "-file", nil)
posix.exit(69)
case:
if !wait_for(t, pid) { return }
log.debug("Odin code has been compiled!")
}
}
c_buf: [dynamic]byte
defer delete(c_buf)
c_out := get_output(t, &c_buf, #directory + "/structs/c_structs", nil)
odin_buf: [dynamic]byte
defer delete(odin_buf)
odin_out := get_output(t, &odin_buf, #directory + "/structs/odin_structs", nil)
testing.expectf(t, c_out == odin_out, "The C output and Odin output differ!\nC output:\n%s\n\n\n\nOdin Output:\n%s", c_out, odin_out)
/* ----------- HELPERS ----------- */
wait_for :: proc(t: ^testing.T, pid: posix.pid_t) -> (ok: bool) {
log.debugf("waiting on pid %v", pid)
waiting: for {
status: i32
wpid := posix.waitpid(pid, &status, {})
if wpid == -1 && posix.errno() == .EINTR {
continue
}
if !testing.expectf(t, wpid != -1, "waitpid() failure: %v", posix.strerror()) {
return false
}
switch {
case posix.WIFEXITED(status):
ok = testing.expect_value(t, posix.WEXITSTATUS(status), 0)
break waiting
case posix.WIFSIGNALED(status):
log.errorf("child process raised: %v", posix.strsignal(posix.WTERMSIG(status)))
ok = false
break waiting
case:
log.errorf("unexpected status (this should never happen): %v", status)
ok = false
break waiting
}
}
return
}
get_output :: proc(t: ^testing.T, output: ^[dynamic]byte, cmd: ..cstring) -> (out_str: string) {
log.debugf("capturing output of: %v", cmd)
pipe: [2]posix.FD
if !testing.expect_value(t, posix.pipe(&pipe), posix.result.OK) {
return
}
switch pid := posix.fork(); pid {
case -1:
log.errorf("fork() failed: %s", posix.strerror())
return
case 0:
posix.close(pipe[0])
posix.dup2(pipe[1], 1)
posix.execv(cmd[0], raw_data(cmd[:]))
panic(string(posix.strerror()))
case:
posix.close(pipe[1])
log.debugf("waiting on pid %v", pid)
reader: for {
buf: [256]byte
switch read := posix.read(pipe[0], &buf[0], 256); {
case read < 0:
log.errorf("read output failed: %v", posix.strerror())
return
case read == 0:
break reader
case:
append(output, ..buf[:read])
}
}
wait_for(t, pid)
return string(output[:])
}
}
}