1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#+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[:])
}
}
}
|