File: test_cstdlib.ml

package info (click to toggle)
ocaml-ctypes 0.2.3-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 752 kB
  • ctags: 1,798
  • sloc: ml: 6,625; ansic: 1,584; makefile: 108
file content (367 lines) | stat: -rw-r--r-- 9,343 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
(*
 * Copyright (c) 2013 Jeremy Yallop.
 *
 * This file is distributed under the terms of the MIT License.
 * See the file LICENSE for details.
 *)

open OUnit
open Ctypes
open Unsigned
open Foreign


(*
  Call the functions

     int isisalnum(int)
     int isisalpha(int)
     int isiscntrl(int)
     int isisdigit(int)
     int isisgraph(int)
     int isislower(int)
     int isisprint(int)
     int isispunct(int)
     int isisspace(int)
     int isisupper(int)
     int isisxdigit(int)
*)
let test_isX_functions () =
  let cchar = view ~read:Char.chr ~write:Char.code int in
  let bool = view ~read:((<>)0) ~write:(fun b -> if b then 1 else 0) int in
  let t = (cchar @-> returning bool) in
  let isalnum = foreign "isalnum" t
  and isalpha = foreign "isalpha" t
  and iscntrl = foreign "iscntrl" t
  and isdigit = foreign "isdigit" t
  and isgraph = foreign "isgraph" t
  and islower = foreign "islower" t
  and isprint = foreign "isprint" t
  and ispunct = foreign "ispunct" t
  and isspace = foreign "isspace" t
  and isupper = foreign "isupper" t
  and isxdigit = foreign "isxdigit" t
  in begin
    assert_bool "" (isalnum 'a');
    assert_bool "" (not (isalnum ' '));

    assert_bool "" (isalpha 'x');
    assert_bool "" (not (isalpha ';'));

    assert_bool "" (iscntrl '\r');
    assert_bool "" (not (iscntrl 'a'));

    assert_bool "" (isdigit '2');
    assert_bool "" (not (isdigit 'a'));

    assert_bool "" (isgraph '?');
    assert_bool "" (not (isgraph ' '));

    assert_bool "" (islower 's');
    assert_bool "" (not (islower 'S'));

    assert_bool "" (isprint ' ');
    assert_bool "" (not (isprint '\b'));

    assert_bool "" (ispunct '.');
    assert_bool "" (not (ispunct 'a'));

    assert_bool "" (isspace '\t');
    assert_bool "" (not (isspace '~'));

    assert_bool "" (isupper 'X');
    assert_bool "" (not (isupper 'x'));

    assert_bool "" (isxdigit 'f');
    assert_bool "" (not (isxdigit 'g'));
  end


(*
  Call the functions

    char *strchr(const char *str, int c);
    int strcmp(const char *str1, const char *str2);
*)
let test_string_functions () =
  (* char *strchr(const char *str, int c);  *)
  let strchr = foreign "strchr" (string @-> int @-> returning string) in

  (* int strcmp(const char *str1, const char *str2);  *)
  let strcmp = foreign "strcmp" (string @-> string @-> returning int) in

  (* int memcmp(const void *ptr1, const void *ptr2, size_t num) *)
  let memcmp = foreign "memcmp"
    (ptr void @-> ptr void @-> size_t @-> returning int) in

  (* void  *memset(void *ptr, int value, size_t num) *)
  let memset = foreign "memset"
    (ptr void @-> int @-> size_t @-> returning (ptr void)) in

  assert_equal "efg" (strchr "abcdefg" (Char.code 'e'))
    ~printer:(fun x -> x);

  (* non-word-aligned pointers do not trigger exceptions *)
  assert_equal "defg" (strchr "abcdefg" (Char.code 'd'));

  assert_bool "strcmp('abc', 'def') < 0"
    (strcmp "abc" "def" < 0);

  assert_bool "strcmp('def', 'abc') > 0"
    (strcmp "def" "abc" > 0);

  assert_bool "strcmp('abc', 'abc') == 0"
    (strcmp "abc" "abc" = 0);

  let p1 = allocate int 10 and p2 = allocate int 20 in
  assert_bool "memcmp(&10, &20) < 0"
    (memcmp (to_voidp p1) (to_voidp p2) (Size_t.of_int (sizeof int)) < 0);

  let p = allocate_n uchar 12 in
  let i = 44 in
  let u = UChar.of_int i in begin
    ignore (memset (to_voidp p) i (Size_t.of_int 12));
    for i = 0 to 11 do
      assert_equal u !@(p +@ i)
    done
  end


(*
  Call the functions

     div_t div(int numerator, int denominator)

  where div_t is defined as follows:

    typedef struct
      {
        int quot;			/* Quotient.  */
        int rem;			/* Remainder.  */
      } div_t;
*)
let test_div () =
  let module M = struct
    type div_t
    let div_t : div_t structure typ = structure "div_t"
    let (-:) ty label = field div_t label ty
    let quot = int -: "quot"
    let rem  = int -: "rem"
    let () = seal div_t

    let div = foreign "div" (int @-> int @-> returning div_t)

    let test ~num ~dem ~quotient ~remainder =
      let v = div num dem in
      let () = assert_equal quotient (getf v quot) in
      let () = assert_equal remainder (getf v rem) in
      ()

    let () = test ~num:10 ~dem:2 ~quotient:5 ~remainder:0

    let () = test ~num:11 ~dem:2 ~quotient:5 ~remainder:1
  end in ()


(*
  Call the function

     void qsort(void *base, size_t nmemb, size_t size,
                int(*compar)(const void *, const void *));
*)
let test_qsort () =
  let comparator = ptr void @-> ptr void @-> returning int in
  let qsort = foreign "qsort"
    (ptr void @-> size_t @-> size_t @-> funptr comparator @->
     returning void) in

  let sortby (type a) (typ : a typ) (f : a -> a -> int) (l : a list) =
    let open Array in
    let open Size_t in
    let open Infix in
    let arr = of_list typ l in
    let len = of_int (length arr) in
    let size = of_int (sizeof typ) in
    let cmp xp yp =
      let x = !@(from_voidp typ xp)
      and y = !@(from_voidp typ yp) in
      f x y
    in
    let () = qsort (to_voidp (start arr)) len size cmp in
    to_list arr
    in

    assert_equal
      [5; 4; 3; 2; 1]
      (sortby int (fun x y -> - (compare x y)) [3; 4; 1; 2; 5]);

    assert_equal
      ['o'; 'q'; 'r'; 's'; 't']
      (sortby char compare ['q'; 's'; 'o'; 'r'; 't'])


(*
  Call the function

     void *bsearch(const void *key, const void *base,
                   size_t nmemb, size_t size,
                   int (*compar)(const void *, const void *));
*)
let test_bsearch () =
  let module M = struct
    let comparator = ptr void @-> ptr void @-> returning int
    let bsearch = foreign "bsearch"
      (ptr void @-> ptr void @-> size_t @-> size_t @-> funptr comparator @->
       returning (ptr void))

    let qsort = foreign "qsort"
      (ptr void @-> size_t @-> size_t @-> funptr comparator @->
       returning void)
    let strlen = foreign "strlen" (ptr char @-> returning size_t)

    (*
      struct mi {
         int nr;
         char *name;
      } months[] = {
         { 1, "jan" }, { 2, "feb" }, { 3, "mar" }, { 4, "apr" },
         { 5, "may" }, { 6, "jun" }, { 7, "jul" }, { 8, "aug" },
         { 9, "sep" }, {10, "oct" }, {11, "nov" }, {12, "dec" }
      };
    *)
    type mi
    let mi = structure "mi"
    let (-:) ty label = field mi label ty
    let mr   = int      -: "mr"
    let name = ptr char -: "name"
    let () = seal (mi : mi structure typ)

  let of_string : string -> char array =
    fun s ->
      let len = String.length s in
      let arr = Array.make char (len + 1) in
      for i = 0 to len - 1 do
        arr.(i) <- s.[i];
      done;
      arr.(len) <- '\000';
      arr

  let as_string : char ptr -> string =
    fun p ->
      let len = Size_t.to_int (strlen p) in
      let s = String.create len in
      for i = 0 to len - 1 do
        s.[i] <- !@(p +@ i);
      done;
      s

  let mkmi n s =
    let m = make mi in
    setf m mr n;
    setf m name (Array.start s);
    m

  let cmpi m1 m2 =
    let mi1 = from_voidp mi m1 in
    let mi2 = from_voidp mi m2 in
    Pervasives.compare
      (as_string (!@(mi1 |-> name)))
      (as_string (!@(mi2 |-> name)))

  let jan = of_string "jan"
  let feb = of_string "feb"
  let mar = of_string "mar"
  let apr = of_string "apr"
  let may = of_string "may"
  let jun = of_string "jun"
  let jul = of_string "jul"
  let aug = of_string "aug"
  let sep = of_string "sep"
  let oct = of_string "oct"
  let nov = of_string "nov"
  let dec = of_string "dec"

  let months = Array.of_list mi [
    mkmi 1 jan;
    mkmi 2 feb;
    mkmi 3 mar;
    mkmi 4 apr;
    mkmi 5 may;
    mkmi 6 jun;
    mkmi 7 jul;
    mkmi 8 aug;
    mkmi 9 sep;
    mkmi 10 oct;
    mkmi 11 nov;
    mkmi 12 dec;
  ]

  let () = qsort
    (to_voidp (Array.start months))
    (Size_t.of_int (Array.length months))
    (Size_t.of_int (sizeof mi))
    cmpi

  let search : mi structure -> mi structure array -> mi structure option
    = fun key array ->
      let len = Size_t.of_int (Array.length array) in
      let size = Size_t.of_int (sizeof mi) in
      let r : unit ptr =
        bsearch
          (to_voidp (addr key))
          (to_voidp (Array.start array))
          len size cmpi in
      if r = null then None
      else Some (!@(from_voidp mi r))

  let find_month_by_name : char array -> mi structure option =
    fun s -> search (mkmi 0 s) months

  let () = match find_month_by_name dec with
      Some m -> assert_equal 12 (getf m mr)
    | _ -> assert false

  let () = match find_month_by_name feb with
      Some m -> assert_equal 2 (getf m mr)
    | _ -> assert false

  let () = match find_month_by_name jan with
      Some m -> assert_equal 1 (getf m mr)
    | _ -> assert false

  let () = match find_month_by_name may with
      Some m -> assert_equal 5 (getf m mr)
    | _ -> assert false

  let missing = of_string "missing"
  let () =
    assert_equal None (find_month_by_name missing)

  let empty = of_string ""
  let () =
    assert_equal None (find_month_by_name empty)

  end in ()



let suite = "C standard library tests" >:::
  ["test isX functions"
    >:: test_isX_functions;

   "test string function"
   >:: test_string_functions;

   "test div function"
   >:: test_div;

   "test qsort function"
   >:: test_qsort;

   "test bsearch function"
   >:: test_bsearch;
  ]


let _ =
  run_test_tt_main suite