chiark / gitweb /
src/method-impl.lisp: Initialize `suppliedp' flags properly.
[sod] / src / c-types-test.lisp
1 ;;; -*-lisp-*-
2 ;;;
3 ;;; Test handling of C types
4 ;;;
5 ;;; (c) 2009 Straylight/Edgeware
6 ;;;
7
8 ;;;----- Licensing notice ---------------------------------------------------
9 ;;;
10 ;;; This file is part of the Sensible Object Design, an object system for C.
11 ;;;
12 ;;; SOD is free software; you can redistribute it and/or modify
13 ;;; it under the terms of the GNU General Public License as published by
14 ;;; the Free Software Foundation; either version 2 of the License, or
15 ;;; (at your option) any later version.
16 ;;;
17 ;;; SOD is distributed in the hope that it will be useful,
18 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;;; GNU General Public License for more details.
21 ;;;
22 ;;; You should have received a copy of the GNU General Public License
23 ;;; along with SOD; if not, write to the Free Software Foundation,
24 ;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26 (cl:in-package #:sod-test)
27
28 ;;;--------------------------------------------------------------------------
29 ;;; Here we go.
30
31 (defclass c-types-test (test-case) ())
32 (add-test *sod-test-suite* (get-suite c-types-test))
33
34 ;;;--------------------------------------------------------------------------
35 ;;; Utilities.
36
37 (defun assert-cteqp (a b)
38   (unless (c-type-equal-p a b)
39     (failure "Assert equal C types: ~A ~_and ~A" a b)))
40
41 (defun assert-not-cteqp (a b)
42   (when (c-type-equal-p a b)
43     (failure "Assert unequal C types: ~A ~_and ~A" a b)))
44
45 (defun expand-tabs (string)
46   (with-output-to-string (out)
47     (do ((i 0 (1+ i))
48          (char (char string 0) (char string i))
49          (pos 0))
50         ((>= i (length string)))
51       (case char
52         (#\newline (write-char char out)
53                    (setf pos 0))
54         (#\tab (write-string "        " out :end (- 8 (mod pos 8)))
55                (setf pos (logandc2 (+ pos 8) 7)))
56         (t (write-char char out)
57            (incf pos))))))
58
59 (defun assert-pp-ctype (type kernel string)
60   (let* ((*print-right-margin* 77)
61          (*print-pretty* t)
62          (print (with-output-to-string (out)
63                   (pprint-c-type type out kernel))))
64     (assert-equal (expand-tabs print) (expand-tabs string)
65                   (format nil "Type ~S with kernel ~S ~_prints as `~A' ~_~
66                                rather than `~A'."
67                           type kernel print string))))
68
69 ;;;--------------------------------------------------------------------------
70 ;;; Simple types.
71
72 (def-test-method intern-trivial-simple-type ((test c-types-test) :run nil)
73   (assert-eql (c-type "foo") (make-simple-type "foo")))
74
75 (def-test-method intern-qualified-simple-type ((test c-types-test) :run nil)
76   (assert-eql (c-type ("foo" :const :volatile))
77               (make-simple-type "foo" '(:volatile :const :volatile))))
78
79 (def-test-method mismatch-simple-type ((test c-types-test) :run nil)
80   (assert-not-cteqp (c-type ("foo" :const)) (make-simple-type "foo")))
81
82 (def-test-method print-simple-type ((test c-types-test) :run nil)
83   (assert-pp-ctype (c-type "foo") "f" "foo f"))
84
85 (def-test-method print-simple-type-abs ((test c-types-test) :run nil)
86   (assert-pp-ctype (c-type "foo") nil "foo"))
87
88 ;;;--------------------------------------------------------------------------
89 ;;; Tagged types.
90
91 (def-test-method intern-trivial-tagged-type ((test c-types-test) :run nil)
92   (assert-eql (c-type (struct "foo")) (make-struct-type "foo")))
93
94 (def-test-method intern-trivial-tagged-type ((test c-types-test) :run nil)
95   (assert-eql (c-type (enum "foo" :const :volatile))
96               (make-enum-type "foo" '(:volatile :const :volatile))))
97
98 (def-test-method mismatch-tagged-type ((test c-types-test) :run nil)
99   (assert-not-cteqp (c-type (enum "foo" :restrict))
100                     (make-union-type "foo" '(:restrict))))
101
102 (def-test-method print-struct-type ((test c-types-test) :run nil)
103   (assert-pp-ctype (c-type (struct "foo")) "f" "struct foo f"))
104
105 (def-test-method print-union-type-abs ((test c-types-test) :run nil)
106   (assert-pp-ctype (c-type (union "foo")) nil "union foo"))
107
108 ;;;--------------------------------------------------------------------------
109 ;;; Pointer types.
110
111 (def-test-method intern-trivial-pointer ((test c-types-test) :run nil)
112   (assert-eql (c-type (* "foo"))
113               (make-pointer-type (make-simple-type "foo"))))
114
115 (def-test-method intern-qualified-pointer ((test c-types-test) :run nil)
116   (assert-eql (c-type (* "foo" :const :volatile))
117               (make-pointer-type (make-simple-type "foo")
118                                  '(:volatile :const))))
119
120 (def-test-method intern-double-indirection ((test c-types-test) :run nil)
121   (assert-eql (c-type (* (* "foo")))
122               (make-pointer-type
123                (make-pointer-type (make-simple-type "foo")))))
124
125 (def-test-method non-intern-complex-pointer ((test c-types-test) :run nil)
126   ;; The protocol doesn't specify what we do here; but we want to avoid
127   ;; interning pointers to non-interned types in order to prevent the intern
128   ;; table filling up with cruft.  So test anyway.
129   (let ((a (c-type (* ([] "foo" 16))))
130         (b (make-pointer-type
131             (make-array-type (make-simple-type "foo") '(16)))))
132     (assert-not-eql a b)
133     (assert-cteqp a b)))
134
135 (def-test-method print-pointer ((test c-types-test) :run nil)
136   (assert-pp-ctype (c-type (* char)) "p" "char *p"))
137
138 (def-test-method print-qualified-pointer ((test c-types-test) :run nil)
139   (assert-pp-ctype (c-type (* char :restrict)) "p" "char *restrict p"))
140
141 (def-test-method print-pointer-abs ((test c-types-test) :run nil)
142   (assert-pp-ctype (c-type (* char)) nil "char *"))
143
144 (def-test-method print-qualified-pointer-abs ((test c-types-test) :run nil)
145   (assert-pp-ctype (c-type (* char :const)) nil "char *const"))
146
147 ;;;--------------------------------------------------------------------------
148 ;;; Array types.
149
150 (def-test-method compare-simple-arrays ((test c-types-test) :run nil)
151   (assert-cteqp (c-type ([] int 10))
152                 (make-array-type (make-simple-type "int") (list 10))))
153
154 (def-test-method compare-multiarray-to-v-of-v ((test c-types-test) :run nil)
155   (assert-cteqp (c-type ([] int 10 4))
156                 (c-type ([] ([] int 4) 10))))
157
158 (def-test-method compare-multiarrays ((test c-types-test) :run nil)
159   (assert-cteqp (c-type ([] ([] int 7 6) 10 9 8))
160                 (c-type ([] ([] ([] int 6) 9 8 7) 10))))
161
162 (def-test-method bad-compare-multiarrays ((test c-types-test) :run nil)
163   (assert-not-cteqp (c-type ([] ([] int 7 6) 10 9 8))
164                     (c-type ([] ([] ([] int 6) 9 8 5) 10))))
165
166 (def-test-method compare-misshaped ((test c-types-test) :run nil)
167   (assert-not-cteqp (c-type ([] ([] int 7) 10 9 8))
168                     (c-type ([] ([] ([] int 6) 9 8 7) 10))))
169
170 (def-test-method print-array ((test c-types-test) :run nil)
171   (assert-pp-ctype (c-type ([] ([] int 7 6) 10 9 8)) "foo"
172                    "int foo[10][9][8][7][6]"))
173
174 (def-test-method print-array-abs ((test c-types-test) :run nil)
175   (assert-pp-ctype (c-type ([] ([] int 7 6) 10 9 8)) nil
176                    "int[10][9][8][7][6]"))
177
178 (def-test-method print-array-of-pointers ((test c-types-test) :run nil)
179   (assert-pp-ctype (c-type ([] (* char))) nil "char *[]"))
180
181 (def-test-method print-pointer-to-array ((test c-types-test) :run nil)
182   (assert-pp-ctype (c-type (* ([] char))) nil "char (*)[]"))
183
184 ;;;--------------------------------------------------------------------------
185 ;;; Function types.
186
187 (def-test-method compare-simple-functions ((test c-types-test) :run nil)
188   ;; Argument names don't matter.
189   (assert-cteqp (c-type (fun int ("a" int) ("b" double)))
190                 (make-function-type (make-simple-type "int")
191                                     (list
192                                      (make-argument "foo"
193                                                     (make-simple-type "int"))
194                                      (make-argument "bar"
195                                                     (c-type double))))))
196
197 (def-test-method build-argument-tail ((test c-types-test) :run nil)
198   (assert-cteqp (c-type (fun int ("a" int) ("b" double)))
199                 (c-type (fun int ("foo" int)
200                              . (list (make-argument "bar"
201                                                     (c-type double)))))))
202
203 (def-test-method bad-compare-ellipsis ((test c-types-test) :run nil)
204   (assert-not-cteqp (c-type (fun int ("x" int) :ellipsis))
205                     (c-type (fun int ("y" int) ("z" double)))))
206
207 (def-test-method bad-compare-ellipsis ((test c-types-test) :run nil)
208   (assert-not-cteqp (c-type (fun int ("x" int) :ellipsis))
209                     (c-type (fun int ("y" int) ("z" double)))))
210
211 (def-test-method print-signal ((test c-types-test) :run nil)
212   (assert-pp-ctype (c-type (fun (* (fun int (nil int)))
213                                 ("signo" int)
214                                 ("handler" (* (fun int (nil int))))))
215                   "signal"
216                   "int (*signal(int signo, int (*handler)(int)))(int)"))
217
218 (def-test-method print-commentify ((test c-types-test) :run nil)
219   (assert-pp-ctype (commentify-function-type
220                     (c-type (fun int
221                                  ("n" size-t)
222                                  (nil string)
223                                  ("format" const-string)
224                                  :ellipsis)))
225                    "snprintf"
226                    (concatenate 'string
227                                 "int snprintf(size_t /*n*/, char *, "
228                                              "const char */*format*/, "
229                                              "...)")))
230
231 (def-test-method commentify-non-recursive ((test c-types-test) :run nil)
232   ;; Also checks pretty-printing.
233   (assert-pp-ctype (commentify-function-type
234                     (c-type (fun int
235                                  ("dirpath" const-string)
236                                  ("fn" (* (fun int
237                                                ("fpath" const-string)
238                                                ("sb" (* (struct "stat"
239                                                                 :const)))
240                                                ("typeflag" int))))
241                                  ("nopenfd" int))))
242                    "ftw"
243                    (format nil "~
244 int ftw
245        (const char */*dirpath*/,
246         int (*/*fn*/)
247                (const char *fpath, const struct stat *sb, int typeflag),
248         int /*nopenfd*/)")))
249
250 ;;;--------------------------------------------------------------------------
251 ;;; Parsing.
252
253 (defun check-c-type-parse (string c-type name)
254   (let* ((char-scanner (make-string-scanner string))
255          (scanner (make-instance 'sod-token-scanner
256                                  :char-scanner char-scanner
257                                  :filename "<none>")))
258     (with-parser-context (token-scanner-context :scanner scanner)
259       (define-module ("<temporary>" :truename nil :location scanner)
260         (multiple-value-bind (result winp consumedp)
261             (parse (seq ((ds (parse-c-type scanner))
262                          (dc (parse-declarator scanner ds))
263                          :eof)
264                      dc))
265           (declare (ignore consumedp))
266           (cond ((null c-type)
267                  (assert-false winp))
268                 (t
269                  (assert-true winp)
270                  (unless (eq c-type t)
271                    (assert-cteqp (car result) c-type))
272                  (unless (eq name t)
273                    (assert-equal (cdr result) name)))))))))
274
275 (def-test-method parse-simple ((test c-types-test) :run nil)
276   (check-c-type-parse "int x" (c-type int) "x"))
277
278 (def-test-method parse-hairy-declspec ((test c-types-test) :run nil)
279   (check-c-type-parse "int long unsigned long y"
280                       (c-type unsigned-long-long) "y"))
281
282 (def-test-method parse-bogus-declspec ((test c-types-test) :run nil)
283   (check-c-type-parse "int long int x" nil nil))
284
285 (def-test-method parse-array ((test c-types-test) :run nil)
286   (check-c-type-parse "float v[69][42]" (c-type ([] float "69" "42")) "v"))
287
288 (def-test-method parse-array-of-pointers ((test c-types-test) :run nil)
289   (check-c-type-parse "const char *const tab[]"
290                       (c-type ([] (* (char :const) :const) ""))
291                       "tab"))
292
293 (def-test-method parse-hairy-function-pointer ((test c-types-test) :run nil)
294   (check-c-type-parse "void (*signal(int, void (*)(int)))(int)"
295                       (c-type (func (* (func void (nil int)))
296                                     (nil int)
297                                     (nil (* (func void (nil int))))))
298                       "signal"))
299
300 ;;;----- That's all, folks --------------------------------------------------