1 ;;;; elisp-compiler.test --- Test the compiler for Elisp.
3 ;;;; Copyright (C) 2009 Free Software Foundation, Inc.
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.
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
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
20 (define-module (test-elisp-compiler)
21 :use-module (test-suite lib)
22 :use-module (system base compile)
23 :use-module (language elisp runtime))
26 ; Macros to handle the compilation conveniently.
28 (define-syntax compile-test
29 (syntax-rules (pass-if pass-if-exception)
30 ((_ (pass-if test-name exp))
31 (pass-if test-name (compile 'exp #:from 'elisp #:to 'value)))
32 ((_ (pass-if test-name exp #:opts opts))
33 (pass-if test-name (compile 'exp #:from 'elisp #:to 'value #:opts opts)))
34 ((_ (pass-if-equal test-name result exp))
35 (pass-if test-name (equal? result
36 (compile 'exp #:from 'elisp #:to 'value))))
37 ((_ (pass-if-exception test-name exc exp))
38 (pass-if-exception test-name exc
39 (compile 'exp #:from 'elisp #:to 'value)))))
41 (define-syntax with-test-prefix/compile
43 ((_ section-name exp ...)
44 (with-test-prefix section-name (compile-test exp) ...))))
47 ; Test control structures.
48 ; ========================
50 (with-test-prefix/compile "Sequencing"
52 (pass-if-equal "progn" 1
59 (setq b (prog1 a (setq a (1+ a))))
60 (and (= a 1) (= b 0))))
64 (setq b (prog2 (setq a (1+ a))
67 (and (= a 3) (= b 2)))))
69 (with-test-prefix/compile "Conditionals"
71 (pass-if-equal "succeeding if" 1
76 (setq a 2) (setq a (1+ a)) a)
78 (equal (if nil 1) nil)))
80 (pass-if-equal "failing when" nil-value
82 (pass-if-equal "succeeding when" 42
84 (when t (setq a 42) a)))
86 (pass-if-equal "failing unless" nil-value
88 (pass-if-equal "succeeding unless" 42
90 (unless nil (setq a 42) a)))
92 (pass-if-equal "empty cond" nil-value
94 (pass-if-equal "all failing cond" nil-value
96 (pass-if-equal "only condition" 5
98 (pass-if-equal "succeeding cond value" 42
99 (cond (nil) (t 42) (t 0)))
100 (pass-if-equal "succeeding cond side-effect" 42
102 (cond (nil) (t (setq a 42) 1) (t (setq a 0)))
105 (with-test-prefix/compile "Combining Conditions"
107 (pass-if-equal "empty and" t-value (and))
108 (pass-if-equal "failing and" nil-value (and 1 2 nil 3))
109 (pass-if-equal "succeeding and" 3 (and 1 2 3))
111 (pass-if-equal "empty or" nil-value (or))
112 (pass-if-equal "failing or" nil-value (or nil nil nil))
113 (pass-if-equal "succeeding or" 1 (or nil 1 nil 2 nil 3))
115 (pass-if-equal "not true" nil-value (not 1))
116 (pass-if-equal "not false" t-value (not nil)))
118 (with-test-prefix/compile "Iteration"
120 (pass-if-equal "failing while" 0
122 (while nil (setq a 1))
124 (pass-if-equal "running while" 120
128 (setq prod (* i prod))
135 (setq b (dotimes (i count)
138 (setq c (dotimes (i 10 42) nil))
139 (and (= a 5050) (equal b nil) (= c 42))))
142 (let ((mylist '(7 2 5)))
144 (setq a (dolist (i mylist)
145 (setq sum (+ sum i))))
146 (setq b (dolist (i mylist 5) 0))
147 (and (= sum (+ 7 2 5))
149 (equal mylist '(7 2 5))
152 (with-test-prefix/compile "Exceptions"
154 (pass-if "catch without exception"
161 (= (catch (+ 1 2) a) 2)))
163 ; FIXME: Figure out how to do this...
164 ;(pass-if-exception "uncaught exception" 'elisp-exception
167 (pass-if "catch and throw"
168 (and (setq mylist '(1 2))
169 (= (catch 'abc (throw 'abc 2) 1) 2)
170 (= (catch 'abc (catch 'def (throw 'abc (1+ 0)) 2) 3) 1)
171 (= (catch 'abc (catch 'def (throw 'def 1) 2) 3) 3)
172 (= (catch mylist (catch '(1 2) (throw mylist 1) 2) 3) 1)))
174 (pass-if "unwind-protect"
175 (progn (setq a 0 b 1 c 1)
177 (unwind-protect (progn (setq a 1)
181 (unwind-protect nil (setq c 0))
182 (and (= a 0) (= b 0) (= c 0)
183 (= (unwind-protect 42 1 2 3) 42)))))
186 ; Test handling of variables.
187 ; ===========================
189 (with-test-prefix/compile "Variable Setting/Referencing"
191 ; TODO: Check for variable-void error
193 (pass-if-equal "setq and reference" 6
194 (progn (setq a 1 b 2 c 3)
196 (pass-if-equal "setq value" 2
197 (progn (setq a 1 b 2)))
199 (pass-if "set and symbol-value"
200 (progn (setq myvar 'a)
201 (and (= (set myvar 42) 42)
203 (= (symbol-value myvar) 42))))
204 (pass-if "void variables"
205 (progn (setq a 1 b 2)
206 (and (eq (makunbound 'b) 'b)
210 (pass-if "disabled void check (all)"
211 (progn (makunbound 'a) a t)
212 #:opts '(#:disable-void-check all))
213 (pass-if "disabled void check (symbol list)"
214 (progn (makunbound 'a) a t)
215 #:opts '(#:disable-void-check (x y a b))))
217 (with-test-prefix/compile "Let and Let*"
219 (pass-if-equal "let without value" nil-value
221 (pass-if-equal "basic let" 0
234 (and (= a 1) (= b 2)))
238 (pass-if "local scope"
246 (with-test-prefix/compile "defconst and defvar"
248 (pass-if-equal "defconst without docstring" 3.141
252 (pass-if-equal "defconst value" 'pi
253 (defconst pi 3.141 "Pi"))
255 (pass-if-equal "defvar without value" 42
259 (pass-if-equal "defvar on already defined variable" 42
261 (defvar a 1 "Some docstring is also ok")
263 (pass-if-equal "defvar on undefined variable" 1
264 (progn (makunbound 'a)
267 (pass-if-equal "defvar value" 'a
271 ; Functions and lambda expressions.
272 ; =================================
274 (with-test-prefix/compile "Lambda Expressions"
276 (pass-if-equal "required arguments" 3
277 ((lambda (a b c) c) 1 2 3))
279 (pass-if-equal "optional argument" 3
280 ((function (lambda (a &optional b c) c)) 1 2 3))
281 (pass-if-equal "optional missing" nil-value
282 ((lambda (&optional a) a)))
284 (pass-if-equal "rest argument" '(3 4 5)
285 ((lambda (a b &rest c) c) 1 2 3 4 5))
286 (pass-if-equal "rest missing" nil-value
287 ((lambda (a b &rest c) c) 1 2)))
289 (with-test-prefix/compile "Function Definitions"
291 (pass-if-equal "defun" 3
292 (progn (defun test (a b) (+ a b))
294 (pass-if-equal "defun value" 'test
295 (defun test (a b) (+ a b)))
297 (pass-if "fset and symbol-function"
298 (progn (setq myfunc 'x x 5)
299 (and (= (fset myfunc 42) 42)
300 (= (symbol-function myfunc) 42)
302 (pass-if "void function values"
304 (defun test (a b) (+ a b))
307 (and (fboundp 'b) (fboundp 'test)
311 (pass-if "flet and flet*"
312 (progn (defun foobar () 42)
313 (defun test () (foobar))
315 (flet ((foobar (lambda () 0))
316 (myfoo (symbol-function 'foobar)))
319 (flet* ((foobar (lambda () 0))
320 (myfoo (symbol-function 'foobar)))
327 (with-test-prefix/compile "Calling Functions"
329 (pass-if-equal "recursion" 120
330 (progn (defun factorial (n prod)
333 (factorial (1- n) (* prod n))))
336 (pass-if "dynamic scoping"
347 ; Quoting and Backquotation.
348 ; ==========================
350 (with-test-prefix/compile "Quotation"
353 (and (equal '42 42) (equal '"abc" "abc")
354 (equal '(1 2 (3 (4) x)) '(1 2 (3 (4) x)))
355 (not (equal '(1 2 (3 4 (x))) '(1 2 3 4 x)))
356 (equal '(1 2 . 3) '(1 2 . 3))))
358 (pass-if "simple backquote"
359 (and (equal (\` 42) 42)
360 (equal (\` (1 (a))) '(1 (a)))
361 (equal (\` (1 . 2)) '(1 . 2))))
363 (progn (setq a 42 l '(18 12))
364 (and (equal (\` (\, a)) 42)
365 (equal (\` (1 a ((\, l)) . (\, a))) '(1 a ((18 12)) . 42)))))
366 (pass-if "unquote splicing"
367 (progn (setq l '(18 12) empty '())
368 (and (equal (\` (\,@ l)) '(18 12))
369 (equal (\` (l 2 (3 (\,@ l)) ((\,@ l)) (\,@ l)))
370 '(l 2 (3 18 12) (18 12) 18 12))
371 (equal (\` (1 2 (\,@ empty) 3)) '(1 2 3))))))
378 (with-test-prefix/compile "Macros"
380 (pass-if-equal "defmacro value" 'magic-number
381 (defmacro magic-number () 42))
383 (pass-if-equal "macro expansion" 1
384 (progn (defmacro take-first (a b) a)
385 (take-first 1 (/ 1 0)))))
388 ; Test the built-ins.
389 ; ===================
391 (with-test-prefix/compile "Equivalence Predicates"
394 (and (equal 2 2) (not (equal 1 2))
395 (equal "abc" "abc") (not (equal "abc" "ABC"))
396 (equal 'abc 'abc) (not (equal 'abc 'def))
397 (equal '(1 2 (3 4) 5) '(1 2 (3 4) 5))
398 (not (equal '(1 2 3 4 5) '(1 2 (3 4) 5)))))
401 (progn (setq some-list '(1 2))
402 (setq some-string "abc")
403 (and (eq 2 2) (not (eq 1 2))
404 (eq 'abc 'abc) (not (eq 'abc 'def))
405 (eq some-string some-string) (not (eq some-string "abc"))
406 (eq some-list some-list) (not (eq some-list '(1 2)))))))
408 (with-test-prefix/compile "Number Built-Ins"
411 (and (floatp 1.0) (not (floatp 1)) (not (floatp 'a))))
413 (and (integerp 42) (integerp -2) (not (integerp 1.0))))
415 (and (numberp 1.0) (numberp -2) (not (numberp 'a))))
417 (and (wholenump 0) (not (wholenump -2)) (not (wholenump 1.0))))
419 (and (zerop 0) (zerop 0.0) (not (zerop 1))))
421 (pass-if "comparisons"
422 (and (= 1 1.0) (/= 0 1)
423 (< 1 2) (> 2 1) (>= 1 1) (<= 1 1)
424 (not (< 1 1)) (not (<= 2 1))))
426 (pass-if "max and min"
427 (and (= (max -5 2 4.0 1) 4.0) (= (min -5 2 4.0 1) -5)
428 (= (max 1) 1) (= (min 1) 1)))
430 (and (= (abs 1.0) 1.0) (= (abs -5) 5)))
433 (and (= (float 1) 1) (= (float 5.5) 5.5)
436 (pass-if-equal "basic arithmetic operators" -8.5
437 (+ (1+ 0) (1- 0) (- 5.5) (* 2 -2) (- 2 1)))
441 (pass-if "floating point rounding"
442 (and (= (ffloor 1.7) 1.0) (= (ffloor -1.2) -2.0) (= (ffloor 1.0) 1.0)
443 (= (fceiling 1.2) 2.0) (= (fceiling -1.7) -1.0) (= (fceiling 1.0) 1.0)
444 (= (ftruncate 1.6) 1.0) (= (ftruncate -1.7) -1.0)
445 (= (fround 1.2) 1.0) (= (fround 1.7) 2.0) (= (fround -1.7) -2.0))))
447 (with-test-prefix/compile "List Built-Ins"
449 (pass-if "consp and atomp"
450 (and (consp '(1 2 3)) (consp '(1 2 . 3)) (consp '(a . b))
451 (not (consp '())) (not (consp 1)) (not (consp "abc"))
452 (atomp 'a) (atomp '()) (atomp -1.5) (atomp "abc")
453 (not (atomp '(1 . 2))) (not (atomp '(1)))))
454 (pass-if "listp and nlistp"
455 (and (listp '(1 2 3)) (listp '(1)) (listp '()) (listp '(1 . 2))
456 (not (listp 'a)) (not (listp 42)) (nlistp 42)
457 (not (nlistp '())) (not (nlistp '(1 2 3))) (not (nlistp '(1 . 2)))))
459 (and (null '()) (not (null 1)) (not (null '(1 2))) (not (null '(1 . 2)))))
461 (pass-if "car and cdr"
462 (and (equal (car '(1 2 3)) 1) (equal (cdr '(1 2 3)) '(2 3))
463 (equal (car '()) nil) (equal (cdr '()) nil)
464 (equal (car '(1 . 2)) 1) (equal (cdr '(1 . 2)) 2)
466 (pass-if "car-safe and cdr-safe"
467 (and (equal (car-safe '(1 2)) 1) (equal (cdr-safe '(1 2)) '(2))
468 (equal (car-safe 5) nil) (equal (cdr-safe 5) nil)))
471 (progn (setq mylist '(a b c))
472 (setq value (pop mylist))
473 (and (equal value 'a)
474 (equal mylist '(b c)))))
475 (pass-if-equal "push" '(a b c)
476 (progn (setq mylist '(b c))
479 (pass-if "nth and nthcdr"
480 (and (equal (nth -5 '(1 2 3)) 1) (equal (nth 3 '(1 2 3)) nil)
481 (equal (nth 0 '(1 2 3)) 1) (equal (nth 2 '(1 2 3)) 3)
482 (equal (nthcdr -5 '(1 2 3)) '(1 2 3))
483 (equal (nthcdr 4 '(1 2 3)) nil)
484 (equal (nthcdr 1 '(1 2 3)) '(2 3))
485 (equal (nthcdr 2 '(1 2 3)) '(3))))
487 (pass-if "cons, list and make-list"
488 (and (equal (cons 1 2) '(1 . 2)) (equal (cons 1 '(2 3)) '(1 2 3))
489 (equal (cons 1 '()) '(1))
490 (equal (list 'a) '(a)) (equal (list) '()) (equal (list 1 2) '(1 2))
491 (equal (make-list 3 42) '(42 42 42))
492 (equal (make-list 0 1) '())))
494 (and (equal (append '(1 2) '(3 4) '(5)) '(1 2 3 4 5))
495 (equal (append '(1 2) 3) '(1 2 . 3))))
497 (and (equal (reverse '(5 4 3 2 1)) '(1 2 3 4 5))
498 (equal (reverse '()) '())))
500 (progn (setq mylist '(1 2 (3 4)))
501 (and (not (eq mylist (copy-tree mylist)))
502 (equal mylist (copy-tree mylist)))))
504 (pass-if "number-sequence"
505 (and (equal (number-sequence 5) '(5))
506 (equal (number-sequence 5 9) '(5 6 7 8 9))
507 (equal (number-sequence 5 9 3) '(5 8))
508 (equal (number-sequence 5 1 -2) '(5 3 1))
509 (equal (number-sequence 5 8 -1) '())
510 (equal (number-sequence 5 1) '())
511 (equal (number-sequence 5 5 0) '(5))))
513 (pass-if "setcar and setcdr"
514 (progn (setq pair '(1 . 2))
516 (setq a (setcar copy 3))
517 (setq b (setcdr copy 4))
519 (equal pair '(3 . 4))))))