Commit | Line | Data |
---|---|---|
025f75b4 MV |
1 | ;;;; optargs.test --- test suite for optional arg processing -*- scheme -*- |
2 | ;;;; Matthias Koeppe <mkoeppe@mail.math.uni-magdeburg.de> --- June 2001 | |
3 | ;;;; | |
581f410f | 4 | ;;;; Copyright (C) 2001, 2006, 2009, 2010, 2013 Free Software Foundation, Inc. |
025f75b4 | 5 | ;;;; |
53befeb7 NJ |
6 | ;;;; This library is free software; you can redistribute it and/or |
7 | ;;;; modify it under the terms of the GNU Lesser General Public | |
8 | ;;;; License as published by the Free Software Foundation; either | |
9 | ;;;; version 3 of the License, or (at your option) any later version. | |
025f75b4 | 10 | ;;;; |
53befeb7 | 11 | ;;;; This library is distributed in the hope that it will be useful, |
025f75b4 | 12 | ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
53befeb7 NJ |
13 | ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | ;;;; Lesser General Public License for more details. | |
025f75b4 | 15 | ;;;; |
53befeb7 NJ |
16 | ;;;; You should have received a copy of the GNU Lesser General Public |
17 | ;;;; License along with this library; if not, write to the Free Software | |
18 | ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
025f75b4 | 19 | |
560434b3 | 20 | (define-module (test-suite test-optargs) |
7ab42fa2 AW |
21 | #:use-module (test-suite lib) |
22 | #:use-module (system base compile) | |
23 | #:use-module (ice-9 optargs)) | |
24 | ||
581f410f AW |
25 | (define exception:invalid-keyword |
26 | '(keyword-argument-error . "Invalid keyword")) | |
27 | ||
ee2a69f5 | 28 | (define exception:unrecognized-keyword |
f6a8e791 | 29 | '(keyword-argument-error . "Unrecognized keyword")) |
ee2a69f5 LC |
30 | |
31 | (define exception:extraneous-arguments | |
f6a8e791 AW |
32 | ;; Message depends on whether we use the interpreter or VM, and on the |
33 | ;; evenness of the number of extra arguments (!). | |
34 | ;'(keyword-argument-error . ".*") | |
35 | '(#t . ".*")) | |
ee2a69f5 | 36 | |
7ab42fa2 AW |
37 | (define-syntax c&e |
38 | (syntax-rules (pass-if pass-if-exception) | |
39 | ((_ (pass-if test-name exp)) | |
40 | (begin (pass-if (string-append test-name " (eval)") | |
41 | (primitive-eval 'exp)) | |
42 | (pass-if (string-append test-name " (compile)") | |
43 | (compile 'exp #:to 'value #:env (current-module))))) | |
44 | ((_ (pass-if-exception test-name exc exp)) | |
45 | (begin (pass-if-exception (string-append test-name " (eval)") | |
46 | exc (primitive-eval 'exp)) | |
47 | (pass-if-exception (string-append test-name " (compile)") | |
48 | exc (compile 'exp #:to 'value | |
49 | #:env (current-module))))))) | |
50 | ||
51 | (define-syntax with-test-prefix/c&e | |
52 | (syntax-rules () | |
53 | ((_ section-name exp ...) | |
54 | (with-test-prefix section-name (c&e exp) ...)))) | |
55 | ||
56 | (with-test-prefix/c&e "optional argument processing" | |
025f75b4 | 57 | (pass-if "local defines work with optional arguments" |
560434b3 DH |
58 | (eval '(begin |
59 | (define* (test-1 #:optional (x 0)) | |
60 | (define d 1) ; local define | |
61 | #t) | |
62 | (false-if-exception (test-1))) | |
63 | (interaction-environment)))) | |
927a122d KR |
64 | |
65 | ;;; | |
66 | ;;; let-keywords | |
67 | ;;; | |
68 | ||
7ab42fa2 | 69 | (with-test-prefix/c&e "let-keywords" |
927a122d KR |
70 | |
71 | ;; in guile 1.6.4 and earlier, an empty binding list only used `begin', | |
72 | ;; which caused apparently internal defines to "leak" out into the | |
73 | ;; encompasing environment | |
74 | (pass-if-exception "empty bindings internal defines leaking out" | |
75 | exception:unbound-var | |
76 | (let ((rest '())) | |
77 | (let-keywords rest #f () | |
78 | (define localvar #f) | |
79 | #f) | |
80 | localvar)) | |
81 | ||
82 | (pass-if "one key" | |
83 | (let-keywords '(#:foo 123) #f (foo) | |
84 | (= foo 123)))) | |
85 | ||
86 | ;;; | |
87 | ;;; let-keywords* | |
88 | ;;; | |
89 | ||
7ab42fa2 | 90 | (with-test-prefix/c&e "let-keywords*" |
927a122d KR |
91 | |
92 | ;; in guile 1.6.4 and earlier, an empty binding list only used `begin', | |
93 | ;; which caused apparently internal defines to "leak" out into the | |
94 | ;; encompasing environment | |
95 | (pass-if-exception "empty bindings internal defines leaking out" | |
96 | exception:unbound-var | |
97 | (let ((rest '())) | |
98 | (let-keywords* rest #f () | |
99 | (define localvar #f) | |
100 | #f) | |
101 | localvar)) | |
102 | ||
103 | (pass-if "one key" | |
104 | (let-keywords* '(#:foo 123) #f (foo) | |
105 | (= foo 123)))) | |
106 | ||
107 | ;;; | |
108 | ;;; let-optional | |
109 | ;;; | |
110 | ||
7ab42fa2 | 111 | (with-test-prefix/c&e "let-optional" |
927a122d KR |
112 | |
113 | ;; in guile 1.6.4 and earlier, an empty binding list only used `begin', | |
114 | ;; which caused apparently internal defines to "leak" out into the | |
115 | ;; encompasing environment | |
116 | (pass-if-exception "empty bindings internal defines leaking out" | |
117 | exception:unbound-var | |
118 | (let ((rest '())) | |
119 | (let-optional rest () | |
120 | (define localvar #f) | |
121 | #f) | |
122 | localvar)) | |
123 | ||
124 | (pass-if "one var" | |
125 | (let ((rest '(123))) | |
126 | (let-optional rest ((foo 999)) | |
127 | (= foo 123))))) | |
128 | ||
129 | ;;; | |
130 | ;;; let-optional* | |
131 | ;;; | |
132 | ||
7ab42fa2 | 133 | (with-test-prefix/c&e "let-optional*" |
927a122d KR |
134 | |
135 | ;; in guile 1.6.4 and earlier, an empty binding list only used `begin', | |
136 | ;; which caused apparently internal defines to "leak" out into the | |
137 | ;; encompasing environment | |
138 | (pass-if-exception "empty bindings internal defines leaking out" | |
139 | exception:unbound-var | |
140 | (let ((rest '())) | |
141 | (let-optional* rest () | |
142 | (define localvar #f) | |
143 | #f) | |
144 | localvar)) | |
145 | ||
146 | (pass-if "one var" | |
147 | (let ((rest '(123))) | |
148 | (let-optional* rest ((foo 999)) | |
149 | (= foo 123))))) | |
7ab42fa2 AW |
150 | |
151 | (define* (foo a b #:optional c (d 1) (e c) f #:key g (h a) (i r) #:rest r) | |
152 | (list a b c d e f g h i r)) | |
153 | ||
154 | ;; So we could use lots more tests here, but the fact that lambda* is in | |
155 | ;; the compiler, and the compiler compiles itself, using the evaluator | |
156 | ;; (when bootstrapping) and compiled code (when doing a partial rebuild) | |
157 | ;; makes me a bit complacent. | |
158 | (with-test-prefix/c&e "define*" | |
159 | (pass-if "the whole enchilada" | |
160 | (equal? (foo 1 2) | |
ee2a69f5 LC |
161 | '(1 2 #f 1 #f #f #f 1 () ()))) |
162 | ||
163 | (pass-if-exception "extraneous arguments" | |
164 | exception:extraneous-arguments | |
165 | (let ((f (lambda* (#:key x) x))) | |
166 | (f 1 2 #:x 'x))) | |
167 | ||
168 | (pass-if-exception "unrecognized keyword" | |
169 | exception:unrecognized-keyword | |
170 | (let ((f (lambda* (#:key x) x))) | |
171 | (f #:y 'not-recognized))) | |
172 | ||
173 | (pass-if "rest given before keywords" | |
174 | ;; Passing the rest argument before the keyword arguments should not | |
175 | ;; prevent keyword argument binding. | |
176 | (let ((f (lambda* (#:key x y z #:rest r) (list x y z r)))) | |
177 | (equal? (f 1 2 3 #:x 'x #:z 'z) | |
178 | '(x #f z (1 2 3 #:x x #:z z)))))) | |
aac006dd | 179 | |
a310a1d1 | 180 | (with-test-prefix/c&e "lambda* inits" |
9a9d82c2 AW |
181 | (pass-if "can bind lexicals within inits" |
182 | (begin | |
d8a071fc AW |
183 | (define qux |
184 | (lambda* (#:optional a #:key (b (or a 13) #:a)) | |
185 | b)) | |
9a9d82c2 AW |
186 | #t)) |
187 | (pass-if "testing qux" | |
188 | (and (equal? (qux) 13) | |
189 | (equal? (qux 1) 1) | |
84b67e19 AW |
190 | (equal? (qux #:a 2) 2))) |
191 | (pass-if "nested lambda* with optional" | |
192 | (begin | |
193 | (define (foo x) | |
194 | (define baz x) | |
195 | (define* (bar #:optional (y baz)) | |
196 | (or (zero? y) (bar (1- y)))) | |
197 | (bar)) | |
198 | (foo 10))) | |
199 | (pass-if "nested lambda* with key" | |
200 | (begin | |
201 | (define (foo x) | |
202 | (define baz x) | |
203 | (define* (bar #:key (y baz)) | |
204 | (or (zero? y) (bar #:y (1- y)))) | |
205 | (bar)) | |
206 | (foo 10)))) | |
207 | ||
9a9d82c2 | 208 | |
aac006dd AW |
209 | (with-test-prefix/c&e "defmacro*" |
210 | (pass-if "definition" | |
211 | (begin | |
212 | (defmacro* transmogrify (a #:optional (b 10)) | |
213 | `(,a ,b)) | |
214 | #t)) | |
215 | ||
216 | (pass-if "explicit arg" | |
217 | (equal? (transmogrify quote 5) | |
218 | 5)) | |
219 | ||
220 | (pass-if "default arg" | |
221 | (equal? (transmogrify quote) | |
222 | 10))) | |
581f410f | 223 | |
19113f1c AW |
224 | (with-test-prefix/c&e "case-lambda" |
225 | (pass-if-exception "no clauses, no args" exception:wrong-num-args | |
226 | ((case-lambda))) | |
227 | ||
228 | (pass-if-exception "no clauses, args" exception:wrong-num-args | |
0426b3f8 MW |
229 | ((case-lambda) 1)) |
230 | ||
231 | (pass-if "docstring" | |
232 | (equal? "docstring test" | |
233 | (procedure-documentation | |
234 | (case-lambda | |
235 | "docstring test" | |
236 | (() 0) | |
237 | ((x) 1)))))) | |
19113f1c | 238 | |
581f410f | 239 | (with-test-prefix/c&e "case-lambda*" |
19113f1c AW |
240 | (pass-if-exception "no clauses, no args" exception:wrong-num-args |
241 | ((case-lambda*))) | |
242 | ||
243 | (pass-if-exception "no clauses, args" exception:wrong-num-args | |
244 | ((case-lambda*) 1)) | |
245 | ||
0426b3f8 MW |
246 | (pass-if "docstring" |
247 | (equal? "docstring test" | |
248 | (procedure-documentation | |
249 | (case-lambda* | |
250 | "docstring test" | |
251 | (() 0) | |
252 | ((x) 1))))) | |
253 | ||
581f410f AW |
254 | (pass-if "unambiguous" |
255 | ((case-lambda* | |
256 | ((a b) #t) | |
257 | ((a) #f)) | |
258 | 1 2)) | |
259 | ||
260 | (pass-if "unambiguous (reversed)" | |
261 | ((case-lambda* | |
262 | ((a) #f) | |
263 | ((a b) #t)) | |
264 | 1 2)) | |
265 | ||
266 | (pass-if "optionals (order disambiguates)" | |
267 | ((case-lambda* | |
268 | ((a #:optional b) #t) | |
269 | ((a b) #f)) | |
270 | 1 2)) | |
271 | ||
272 | (pass-if "optionals (order disambiguates (2))" | |
273 | ((case-lambda* | |
274 | ((a b) #t) | |
275 | ((a #:optional b) #f)) | |
276 | 1 2)) | |
277 | ||
278 | (pass-if "optionals (one arg)" | |
279 | ((case-lambda* | |
280 | ((a b) #f) | |
281 | ((a #:optional b) #t)) | |
282 | 1)) | |
283 | ||
284 | (pass-if "optionals (one arg (2))" | |
285 | ((case-lambda* | |
286 | ((a #:optional b) #t) | |
287 | ((a b) #f)) | |
288 | 1)) | |
289 | ||
290 | (pass-if "keywords without keyword" | |
291 | ((case-lambda* | |
292 | ((a #:key c) #t) | |
293 | ((a b) #f)) | |
294 | 1)) | |
295 | ||
296 | (pass-if "keywords with keyword" | |
297 | ((case-lambda* | |
298 | ((a #:key c) #t) | |
299 | ((a b) #f)) | |
300 | 1 #:c 2)) | |
301 | ||
302 | (pass-if "keywords (too many positionals)" | |
303 | ((case-lambda* | |
304 | ((a #:key c) #f) | |
305 | ((a b) #t)) | |
306 | 1 2)) | |
307 | ||
308 | (pass-if "keywords (order disambiguates)" | |
309 | ((case-lambda* | |
310 | ((a #:key c) #t) | |
311 | ((a b c) #f)) | |
312 | 1 #:c 2)) | |
313 | ||
314 | (pass-if "keywords (order disambiguates (2))" | |
315 | ((case-lambda* | |
316 | ((a b c) #t) | |
317 | ((a #:key c) #f)) | |
318 | 1 #:c 2))) |