1# coding: US-ASCII
2# frozen_string_literal: true
3begin
4  require_relative 'helper'
5  require 'fiddle/import'
6rescue LoadError
7end
8
9module Fiddle
10  module LIBC
11    extend Importer
12    dlload LIBC_SO, LIBM_SO
13
14    typealias 'string', 'char*'
15    typealias 'FILE*', 'void*'
16
17    extern "void *strcpy(char*, char*)"
18    extern "int isdigit(int)"
19    extern "double atof(string)"
20    extern "unsigned long strtoul(char*, char **, int)"
21    extern "int qsort(void*, unsigned long, unsigned long, void*)"
22    extern "int fprintf(FILE*, char*)" rescue nil
23    extern "int gettimeofday(timeval*, timezone*)" rescue nil
24
25    BoundQsortCallback = bind("void *bound_qsort_callback(void*, void*)"){|ptr1,ptr2| ptr1[0] <=> ptr2[0]}
26    Timeval = struct [
27      "long tv_sec",
28      "long tv_usec",
29    ]
30    Timezone = struct [
31      "int tz_minuteswest",
32      "int tz_dsttime",
33    ]
34    MyStruct = struct [
35      "short num[5]",
36      "char c",
37      "unsigned char buff[7]",
38    ]
39
40    CallCallback = bind("void call_callback(void*, void*)"){ | ptr1, ptr2|
41      f = Function.new(ptr1.to_i, [TYPE_VOIDP], TYPE_VOID)
42      f.call(ptr2)
43    }
44  end
45
46  class TestImport < TestCase
47    def test_ensure_call_dlload
48      err = assert_raise(RuntimeError) do
49        Class.new do
50          extend Importer
51          extern "void *strcpy(char*, char*)"
52        end
53      end
54      assert_match(/call dlload before/, err.message)
55    end
56
57    def test_malloc()
58      s1 = LIBC::Timeval.malloc()
59      s2 = LIBC::Timeval.malloc()
60      refute_equal(s1.to_ptr.to_i, s2.to_ptr.to_i)
61    end
62
63    def test_sizeof()
64      assert_equal(SIZEOF_VOIDP, LIBC.sizeof("FILE*"))
65      assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(LIBC::MyStruct))
66      assert_equal(LIBC::MyStruct.size(), LIBC.sizeof(LIBC::MyStruct.malloc()))
67      assert_equal(SIZEOF_LONG_LONG, LIBC.sizeof("long long")) if defined?(SIZEOF_LONG_LONG)
68    end
69
70    Fiddle.constants.grep(/\ATYPE_(?!VOID\z)(.*)/) do
71      type = $&
72      size = Fiddle.const_get("SIZEOF_#{$1}")
73      name = $1.sub(/P\z/,"*").gsub(/_(?!T\z)/, " ").downcase
74      define_method("test_sizeof_#{name}") do
75        assert_equal(size, Fiddle::Importer.sizeof(name), type)
76      end
77    end
78
79    def test_unsigned_result()
80      d = (2 ** 31) + 1
81
82      r = LIBC.strtoul(d.to_s, 0, 0)
83      assert_equal(d, r)
84    end
85
86    def test_io()
87      if( RUBY_PLATFORM != BUILD_RUBY_PLATFORM ) || !defined?(LIBC.fprintf)
88        return
89      end
90      io_in,io_out = IO.pipe()
91      LIBC.fprintf(io_out, "hello")
92      io_out.flush()
93      io_out.close()
94      str = io_in.read()
95      io_in.close()
96      assert_equal("hello", str)
97    end
98
99    def test_value()
100      i = LIBC.value('int', 2)
101      assert_equal(2, i.value)
102
103      d = LIBC.value('double', 2.0)
104      assert_equal(2.0, d.value)
105
106      ary = LIBC.value('int[3]', [0,1,2])
107      assert_equal([0,1,2], ary.value)
108    end
109
110    def test_struct()
111      s = LIBC::MyStruct.malloc()
112      s.num = [0,1,2,3,4]
113      s.c = ?a.ord
114      s.buff = "012345\377"
115      assert_equal([0,1,2,3,4], s.num)
116      assert_equal(?a.ord, s.c)
117      assert_equal([?0.ord,?1.ord,?2.ord,?3.ord,?4.ord,?5.ord,?\377.ord], s.buff)
118    end
119
120    def test_gettimeofday()
121      if( defined?(LIBC.gettimeofday) )
122        timeval = LIBC::Timeval.malloc()
123        timezone = LIBC::Timezone.malloc()
124        LIBC.gettimeofday(timeval, timezone)
125        cur = Time.now()
126        assert(cur.to_i - 2 <= timeval.tv_sec && timeval.tv_sec <= cur.to_i)
127      end
128    end
129
130    def test_strcpy()
131      buff = +"000"
132      str = LIBC.strcpy(buff, "123")
133      assert_equal("123", buff)
134      assert_equal("123", str.to_s)
135    end
136
137    def test_isdigit
138      r1 = LIBC.isdigit(?1.ord)
139      r2 = LIBC.isdigit(?2.ord)
140      rr = LIBC.isdigit(?r.ord)
141      assert_operator(r1, :>, 0)
142      assert_operator(r2, :>, 0)
143      assert_equal(0, rr)
144    end
145
146    def test_atof
147      r = LIBC.atof("12.34")
148      assert_includes(12.00..13.00, r)
149    end
150
151    def test_no_message_with_debug
152      assert_in_out_err(%w[--debug --disable=gems -rfiddle/import], 'p Fiddle::Importer', ['Fiddle::Importer'])
153    end
154  end
155end if defined?(Fiddle)
156