0
|
1 /*
|
|
2
|
|
3 godc_test.go
|
|
4 Copyright (c) 2014 Tassilo Philipp <tphilipp@potion-studios.com>
|
|
5
|
|
6 Permission to use, copy, modify, and distribute this software for any
|
|
7 purpose with or without fee is hereby granted, provided that the above
|
|
8 copyright notice and this permission notice appear in all copies.
|
|
9
|
|
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
17
|
|
18 */
|
|
19
|
|
20
|
|
21 package godc
|
|
22
|
|
23 import (
|
|
24 "testing"
|
|
25 "fmt"
|
|
26 "unsafe"
|
|
27 "math"
|
|
28 )
|
|
29
|
|
30 func TestGoDC(t *testing.T) {
|
|
31 lm := new(ExtLib)
|
|
32 if err := lm.Load("/usr/lib/libm.so"); err != nil {
|
|
33 t.FailNow()
|
|
34 }
|
|
35 defer lm.Free()
|
|
36
|
|
37 if err := lm.SymsInit("/usr/lib/libm.so"); err != nil {
|
|
38 t.FailNow()
|
|
39 }
|
|
40 defer lm.SymsCleanup()
|
|
41
|
|
42 fmt.Printf("Testing dl:\n")
|
|
43 fmt.Printf("-----------\n")
|
|
44 fmt.Printf("Loaded library at address: %p\n", lm.lib)
|
|
45 fmt.Printf("C sqrt function at address: %p\n", lm.FindSymbol("sqrt"))
|
|
46 fmt.Printf("C pow function at address: %p\n\n", lm.FindSymbol("pow"))
|
|
47
|
|
48 fmt.Printf("Testing dlSyms:\n")
|
|
49 fmt.Printf("---------------\n")
|
|
50 fmt.Printf("Symbols in libm: %d\n", lm.SymsCount())
|
|
51 fmt.Printf("Symbol name for address %p: %s\n", lm.FindSymbol("pow"), lm.SymsNameFromValue(lm.FindSymbol("pow")))
|
|
52 fmt.Printf("All symbol names in libm:\n")
|
|
53 for i, n := 0, lm.SymsCount(); i<n; i++ {
|
|
54 fmt.Printf(" %s\n", lm.SymsName(i))
|
|
55 }
|
|
56 fmt.Printf("\n")
|
|
57
|
|
58
|
|
59
|
|
60 // Another lib
|
|
61 lc := new(ExtLib)
|
|
62 if err := lc.Load("/usr/lib/libc.so"); err != nil {
|
|
63 t.FailNow()
|
|
64 }
|
|
65 defer lc.Free()
|
|
66
|
|
67 if err := lc.SymsInit("/usr/lib/libc.so"); err != nil {
|
|
68 t.FailNow()
|
|
69 }
|
|
70 defer lc.SymsCleanup()
|
|
71
|
|
72 fmt.Printf("Symbols in libc: %d (not listing them here, too many)\n\n", lc.SymsCount())
|
|
73
|
|
74
|
|
75
|
|
76 // Call some functions
|
|
77 fmt.Printf("Testing dc:\n")
|
|
78 fmt.Printf("-----------\n")
|
|
79 vm := new(CallVM)
|
|
80 if err := vm.InitCallVM(); err != nil {
|
|
81 t.FailNow()
|
|
82 }
|
|
83 defer vm.Free()
|
|
84
|
|
85 vm.Mode(DC_CALL_C_DEFAULT)
|
|
86
|
|
87
|
|
88 // Float
|
|
89 vm.Reset()
|
|
90 vm.ArgFloat(36)
|
|
91 rf := vm.CallFloat(lm.FindSymbol("sqrtf"))
|
|
92 fmt.Printf("sqrtf(36) = %f\n", rf)
|
|
93 if(rf != 6.0) { t.FailNow() }
|
|
94
|
|
95 vm.Reset() // Test reset, reusing VM
|
|
96 vm.ArgDouble(3.6)
|
|
97 rd := vm.CallDouble(lm.FindSymbol("floor"))
|
|
98 fmt.Printf("floor(3.6) = %f\n", rd)
|
|
99 if(rd != 3.0) { t.FailNow() }
|
|
100
|
|
101
|
|
102 // Double
|
|
103 vm.Reset()
|
|
104 vm.ArgDouble(4.2373)
|
|
105 rd = vm.CallDouble(lm.FindSymbol("sqrt"))
|
|
106 fmt.Printf("sqrt(4.2373) = %f\n", rd)
|
|
107 if(math.Abs(rd - 2.05847) > 0.00001) { t.FailNow() }
|
|
108
|
|
109 vm.Reset()
|
|
110 vm.ArgDouble(2.373)
|
|
111 vm.ArgDouble(-1000) // 2 args
|
|
112 rd = vm.CallDouble(lm.FindSymbol("copysign"))
|
|
113 fmt.Printf("copysign(2.373, -1000) = %f\n", rd)
|
|
114 if(rd != -2.373) { t.FailNow() }
|
|
115
|
|
116
|
|
117 // Strings
|
|
118 vm.Reset()
|
|
119 cs1 := vm.AllocCString("/return/only/this_here")
|
|
120 defer vm.FreeCString(cs1)
|
|
121
|
|
122 vm.ArgPointer(cs1)
|
|
123 rs := vm.CallPointerToStr(lc.FindSymbol("basename"))
|
|
124 fmt.Printf("basename(\"/return/only/this_here\") = %s\n", rs)
|
|
125 if(rs != "this_here") { t.FailNow() }
|
|
126 // Reuse path
|
|
127 rs = vm.CallPointerToStr(lc.FindSymbol("dirname"))
|
|
128 fmt.Printf("dirname(\"/return/only/this_here\") = %s\n", rs)
|
|
129 if(rs != "/return/only") { t.FailNow() }
|
|
130
|
|
131
|
|
132 // Integer
|
|
133 vm.Reset()
|
|
134 vm.ArgInt('a')
|
|
135 ri := vm.CallInt(lc.FindSymbol("toupper"))
|
|
136 fmt.Printf("toupper('a') = %c\n", ri)
|
|
137 if(ri != 'A') { t.FailNow() }
|
|
138
|
|
139 vm.Reset()
|
|
140 vm.ArgInt('a')
|
|
141 ri = vm.CallInt(lc.FindSymbol("tolower"))
|
|
142 fmt.Printf("tolower('a') = %c\n", ri)
|
|
143 if(ri != 'a') { t.FailNow() }
|
|
144
|
|
145 vm.Reset()
|
|
146 vm.ArgInt('R')
|
|
147 ri = vm.CallInt(lc.FindSymbol("toupper"))
|
|
148 fmt.Printf("toupper('R') = %c\n", vm.CallInt(lc.FindSymbol("toupper")))
|
|
149 if(ri != 'R') { t.FailNow() }
|
|
150
|
|
151 vm.Reset()
|
|
152 vm.ArgInt('R')
|
|
153 ri = vm.CallInt(lc.FindSymbol("tolower"))
|
|
154 fmt.Printf("tolower('R') = %c\n", vm.CallInt(lc.FindSymbol("tolower")))
|
|
155 if(ri != 'r') { t.FailNow() }
|
|
156
|
|
157
|
|
158 // Integer return
|
|
159 vm.Reset()
|
|
160 cs2 := vm.AllocCString("Tassilo")
|
|
161 defer vm.FreeCString(cs2)
|
|
162
|
|
163 fmt.Printf("rand() = %d\n", vm.CallInt(lc.FindSymbol("rand")))
|
|
164 fmt.Printf("rand() = %d\n", vm.CallInt(lc.FindSymbol("rand")))
|
|
165 fmt.Printf("rand() = %d\n", vm.CallInt(lc.FindSymbol("rand")))
|
|
166 fmt.Printf("rand() = %d\n", vm.CallInt(lc.FindSymbol("rand")))
|
|
167 fmt.Printf("rand() = %d\n", vm.CallInt(lc.FindSymbol("rand")))
|
|
168 vm.ArgPointer(cs2)
|
|
169 ri = vm.CallInt(lc.FindSymbol("strlen"))
|
|
170 fmt.Printf("strlen(\"Tassilo\") = %d\n", ri)
|
|
171 if(ri != 7) { t.FailNow() }
|
|
172
|
|
173
|
|
174 // Formatted - with signature/conversion
|
|
175 vm.Reset()
|
|
176 vm.ArgF("dd)d", 3.14, -2000) // 2 args, second passed as int, but ArgF will convert
|
|
177 rd = vm.CallDouble(lm.FindSymbol("copysign"))
|
|
178 fmt.Printf("dd)d: copysign(3.14, -2000) = %f\n", rd)
|
|
179 if(rd != -3.14) { t.FailNow() }
|
|
180
|
|
181 // Formatted - without signature/conversion
|
|
182 vm.Reset()
|
|
183 vm.ArgF("dd)d", -31.4, 42.4) // 2 args, second passed as int, but ArgF will convert
|
|
184 rd = vm.CallDouble(lm.FindSymbol("copysign"))
|
|
185 fmt.Printf("dd)d: copysign(-31.4, 42.4) = %f\n", rd)
|
|
186 if(rd != 31.4) { t.FailNow() }
|
|
187
|
|
188 // Formatted - use Go's types, pass unsupported type, should return an error
|
|
189 vm.Reset()
|
|
190 err := vm.ArgF_Go(6.14, vm)
|
|
191 fmt.Printf("ArgF_Go: copysign(6.14, <unsupported type>) should return error: %t\n", err != nil)
|
|
192 if(err == nil) { t.FailNow() }
|
|
193
|
|
194 // Formatted - use Go's types
|
|
195 vm.Reset()
|
|
196 vm.ArgF_Go(-61.4, 42.4) // 2 args, both need to be correct or undefined behaviour
|
|
197 rd = vm.CallDouble(lm.FindSymbol("copysign"))
|
|
198 fmt.Printf("copysign(-61.4, 42.4) = %f\n", rd)
|
|
199 if(rd != 61.4) { t.FailNow() }
|
|
200
|
|
201
|
|
202 // Ellipse
|
|
203 vm.Mode(DC_CALL_C_ELLIPSIS)
|
|
204 vm.Reset()
|
|
205 buf := make([]byte, 1000)
|
|
206 bufPtr := unsafe.Pointer(&buf[0])
|
|
207 cs3 := vm.AllocCString("Four:%d | \"Hello\":%s | Pi:%f")
|
|
208 cs4 := vm.AllocCString("Hello")
|
|
209 defer vm.FreeCString(cs4)
|
|
210 defer vm.FreeCString(cs3)
|
|
211
|
|
212 vm.ArgPointer(bufPtr)
|
|
213 vm.ArgPointer(cs3)
|
|
214 vm.Mode(DC_CALL_C_ELLIPSIS_VARARGS)
|
|
215 vm.ArgInt(4)
|
|
216 vm.ArgPointer(cs4)
|
|
217 vm.ArgDouble(3.14) // Double, b/c of ... promotion rules
|
|
218 ri = vm.CallInt(lc.FindSymbol("sprintf"))
|
|
219 fmt.Printf("sprintf(bufPtr, \"Four:%%d | \\\"Hello\\\":%%s | Pi:%%f\", 4, \"Hello\", 3.14) = %d:\n", ri)
|
|
220 fmt.Printf(" bufPtr: %s\n", string(buf[/*slice printed bytes*/:ri]))
|
|
221 if(ri != 36) { t.FailNow() }
|
|
222
|
|
223
|
|
224 //@@@ untested:
|
|
225 // - ArgF and ArgF_Go with strings
|
|
226 // - ArgF and ArgF_Go with bools
|
|
227 // - ...
|
|
228 }
|
|
229
|