structs.odin 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. //+build darwin, freebsd, openbsd, netbsd
  2. package tests_core_posix
  3. import "core:log"
  4. import "core:testing"
  5. import "core:sys/posix"
  6. // This test tests some of the process APIs of posix while also double checking size and alignment
  7. // of the structs we bound.
  8. @(test)
  9. execute_struct_checks :: proc(t: ^testing.T) {
  10. log.debug("compiling C project")
  11. {
  12. switch pid := posix.fork(); pid {
  13. case -1:
  14. log.errorf("fork() failed: %s", posix.strerror())
  15. case 0:
  16. c_compiler := posix.getenv("CC")
  17. if c_compiler == nil {
  18. c_compiler = "clang"
  19. }
  20. posix.execlp(c_compiler,
  21. c_compiler, #directory + "/structs/structs.c", "-o", #directory + "/structs/c_structs", nil)
  22. posix.exit(69)
  23. case:
  24. if !wait_for(t, pid) { return }
  25. log.debug("C code has been compiled!")
  26. }
  27. }
  28. log.debug("compiling Odin project")
  29. {
  30. switch pid := posix.fork(); pid {
  31. case -1:
  32. log.errorf("fork() failed: %s", posix.strerror())
  33. case 0:
  34. posix.execlp(ODIN_ROOT + "/odin",
  35. ODIN_ROOT + "/odin", "build", #directory + "/structs/structs.odin", "-out:" + #directory + "/structs/odin_structs", "-file", nil)
  36. posix.exit(69)
  37. case:
  38. if !wait_for(t, pid) { return }
  39. log.debug("Odin code has been compiled!")
  40. }
  41. }
  42. c_buf: [dynamic]byte
  43. defer delete(c_buf)
  44. c_out := get_output(t, &c_buf, #directory + "/structs/c_structs", nil)
  45. odin_buf: [dynamic]byte
  46. defer delete(odin_buf)
  47. odin_out := get_output(t, &odin_buf, #directory + "/structs/odin_structs", nil)
  48. 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)
  49. /* ----------- HELPERS ----------- */
  50. wait_for :: proc(t: ^testing.T, pid: posix.pid_t) -> (ok: bool) {
  51. log.debugf("waiting on pid %v", pid)
  52. waiting: for {
  53. status: i32
  54. wpid := posix.waitpid(pid, &status, {})
  55. if !testing.expectf(t, wpid != -1, "waitpid() failure: %v", posix.strerror()) {
  56. return false
  57. }
  58. switch {
  59. case posix.WIFEXITED(status):
  60. ok = testing.expect_value(t, posix.WEXITSTATUS(status), 0)
  61. break waiting
  62. case posix.WIFSIGNALED(status):
  63. log.errorf("child process raised: %v", posix.strsignal(posix.WTERMSIG(status)))
  64. ok = false
  65. break waiting
  66. case:
  67. log.errorf("unexpected status (this should never happen): %v", status)
  68. ok = false
  69. break waiting
  70. }
  71. }
  72. return
  73. }
  74. get_output :: proc(t: ^testing.T, output: ^[dynamic]byte, cmd: ..cstring) -> (out_str: string) {
  75. log.debugf("capturing output of: %v", cmd)
  76. pipe: [2]posix.FD
  77. if !testing.expect_value(t, posix.pipe(&pipe), posix.result.OK) {
  78. return
  79. }
  80. switch pid := posix.fork(); pid {
  81. case -1:
  82. log.errorf("fork() failed: %s", posix.strerror())
  83. return
  84. case 0:
  85. posix.close(pipe[0])
  86. posix.dup2(pipe[1], 1)
  87. posix.execv(cmd[0], raw_data(cmd[:]))
  88. panic(string(posix.strerror()))
  89. case:
  90. posix.close(pipe[1])
  91. log.debugf("waiting on pid %v", pid)
  92. reader: for {
  93. buf: [256]byte
  94. switch read := posix.read(pipe[0], &buf[0], 256); {
  95. case read < 0:
  96. log.errorf("read output failed: %v", posix.strerror())
  97. return
  98. case read == 0:
  99. break reader
  100. case:
  101. append(output, ..buf[:read])
  102. }
  103. }
  104. wait_for(t, pid)
  105. return string(output[:])
  106. }
  107. }
  108. }