1# coding: US-ASCII
2require_relative 'test_base'
3require 'dl/import'
4
5module DL
6  module LIBC
7    extend Importer
8    dlload LIBC_SO, LIBM_SO
9
10    typealias 'string', 'char*'
11    typealias 'FILE*', 'void*'
12
13    extern "void *strcpy(char*, char*)"
14    extern "int isdigit(int)"
15    extern "double atof(string)"
16    extern "unsigned long strtoul(char*, char **, int)"
17    extern "int qsort(void*, unsigned long, unsigned long, void*)"
18    extern "int fprintf(FILE*, char*)"
19    extern "int gettimeofday(timeval*, timezone*)" rescue nil
20
21    QsortCallback = bind("void *qsort_callback(void*, void*)", :temp)
22    BoundQsortCallback = bind("void *bound_qsort_callback(void*, void*)"){|ptr1,ptr2| ptr1[0] <=> ptr2[0]}
23    Timeval = struct [
24      "long tv_sec",
25      "long tv_usec",
26    ]
27    Timezone = struct [
28      "int tz_minuteswest",
29      "int tz_dsttime",
30    ]
31    MyStruct = struct [
32      "short num[5]",
33      "char c",
34      "unsigned char buff[7]",
35    ]
36
37    CallCallback = bind("void call_callback(void*, void*)"){|ptr1, ptr2|
38      f = Function.new(CFunc.new(ptr1.to_i, TYPE_VOID, "<anonymous>"), [TYPE_VOIDP])
39      f.call(ptr2)
40    }
41    CarriedFunction = bind("void callback_function(void*)", :carried, 0)
42  end
43
44  class TestImport < TestBase
45    def test_ensure_call_dlload
46      err = assert_raises(RuntimeError) do
47        Class.new do
48          extend Importer
49          extern "void *strcpy(char*, char*)"
50        end
51      end
52      assert_match(/call dlload before/, err.message)
53    end
54
55    def test_malloc()
56      s1 = LIBC::Timeval.malloc()
57      s2 = LIBC::Timeval.malloc()
58      assert_not_equal(s1.to_ptr.to_i, s2.to_ptr.to_i)
59    end
60
61    def test_sizeof()
62      assert_equal(SIZEOF_VOIDP, LIBC.sizeof("FILE*"))
63      assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(LIBC::MyStruct))
64    end
65
66    def test_unsigned_result()
67      d = (2 ** 31) + 1
68
69      r = LIBC.strtoul(d.to_s, 0, 0)
70      assert_equal(d, r)
71    end
72
73    def test_io()
74      if( RUBY_PLATFORM != BUILD_RUBY_PLATFORM )
75        return
76      end
77      io_in,io_out = IO.pipe()
78      LIBC.fprintf(io_out, "hello")
79      io_out.flush()
80      io_out.close()
81      str = io_in.read()
82      io_in.close()
83      assert_equal("hello", str)
84    end
85
86    def test_value()
87      i = LIBC.value('int', 2)
88      assert_equal(2, i.value)
89
90      d = LIBC.value('double', 2.0)
91      assert_equal(2.0, d.value)
92
93      ary = LIBC.value('int[3]', [0,1,2])
94      assert_equal([0,1,2], ary.value)
95    end
96
97    def test_carried_function()
98      data1 = "data"
99      data2 = nil
100      LIBC.call_callback(LIBC::CarriedFunction, LIBC::CarriedFunction.create_carrier(data1)){|d|
101        data2 = d
102      }
103      assert_equal(data1, data2)
104    end
105
106    def test_struct()
107      s = LIBC::MyStruct.malloc()
108      s.num = [0,1,2,3,4]
109      s.c = ?a.ord
110      s.buff = "012345\377"
111      assert_equal([0,1,2,3,4], s.num)
112      assert_equal(?a.ord, s.c)
113      assert_equal([?0.ord,?1.ord,?2.ord,?3.ord,?4.ord,?5.ord,?\377.ord], s.buff)
114    end
115
116    def test_gettimeofday()
117      if( defined?(LIBC.gettimeofday) )
118        timeval = LIBC::Timeval.malloc()
119        timezone = LIBC::Timezone.malloc()
120        LIBC.gettimeofday(timeval, timezone)
121        cur = Time.now()
122        assert(cur.to_i - 2 <= timeval.tv_sec && timeval.tv_sec <= cur.to_i)
123      end
124    end
125
126    def test_strcpy()
127      buff = "000"
128      str = LIBC.strcpy(buff, "123")
129      assert_equal("123", buff)
130      assert_equal("123", str.to_s)
131    end
132
133    def test_isdigit()
134      r1 = LIBC.isdigit(?1.ord)
135      r2 = LIBC.isdigit(?2.ord)
136      rr = LIBC.isdigit(?r.ord)
137      assert_positive(r1)
138      assert_positive(r2)
139      assert_zero(rr)
140    end
141
142    def test_atof()
143      r = LIBC.atof("12.34")
144      assert_match(12.00..13.00, r)
145    end
146
147    def test_strtod()
148      f = Function.new(CFunc.new(@libc['strtod'], TYPE_DOUBLE, 'strtod'),
149                       [TYPE_VOIDP, TYPE_VOIDP])
150      buff1 = "12.34"
151      buff2 = "     "
152      r = f.call(buff1, buff2)
153      assert_match(12.00..13.00, r)
154    end
155
156    def test_qsort()
157      buff = "9341"
158      LIBC.qsort(buff, buff.size, 1, LIBC::QsortCallback){|ptr1,ptr2| ptr1[0] <=> ptr2[0]}
159      assert_equal("1349", buff)
160      buff = "9341"
161      LIBC.qsort(buff, buff.size, 1, LIBC::BoundQsortCallback)
162      assert_equal("1349", buff)
163    end
164  end
165end
166