source: trunk/abcl/test/lisp/abcl/clos-tests.lisp

Last change on this file was 15742, checked in by Mark Evenson, 6 months ago

Test for propagation of change to existing CLOS instances

File size: 17.6 KB
Line 
1
2;;; clos-tests.lisp
3;;;
4;;; Copyright (C) 2010 Erik Huelsmann
5;;;
6;;; This program is free software; you can redistribute it and/or
7;;; modify it under the terms of the GNU General Public License
8;;; as published by the Free Software Foundation; either version 2
9;;; of the License, or (at your option) any later version.
10;;;
11;;; This program 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
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20
21;; These tests are in clos tests, because e.g. D-M-C isn't mop, but *is* clos
22
23(in-package #:abcl.test.lisp)
24
25
26;; tests for D-M-C, long form, some taken from SBCL
27
28;; D-M-C should return the name of the new method combination, nothing else.
29
30(deftest dmc-return.1
31    (define-method-combination dmc-test-return-foo)
32  dmc-test-return-foo)
33
34(deftest dmc-return.2
35    (define-method-combination dmc-test-return-bar :operator and)
36  dmc-test-return-bar)
37
38(deftest dmc-return.3
39    (define-method-combination dmc-test-return
40        (&optional (order :most-specific-first))
41      ((around (:around))
42       (primary (dmc-test-return) :order order :required t))
43      (let ((form (if (rest primary)
44                      `(and ,@(mapcar #'(lambda (method)
45                                          `(call-method ,method))
46                                      primary))
47                      `(call-method ,(first primary)))))
48        (if around
49            `(call-method ,(first around)
50                          (,@(rest around)
51                             (make-method ,form)))
52            form)))
53  dmc-test-return)
54
55;; A method combination which originally failed;
56;;   for different reasons in SBCL than in ABCL (hence leaving out
57;;   the original comment)
58
59(define-method-combination dmc-test-mc.1
60    (&optional (order :most-specific-first))
61  ((around (:around))
62   (primary (dmc-test-mc) :order order :required t))
63  (let ((form (if (rest primary)
64                  `(and ,@(mapcar #'(lambda (method)
65                                      `(call-method ,method))
66                                  primary))
67                  `(call-method ,(first primary)))))
68    (if around
69        `(call-method ,(first around)
70                      (,@(rest around)
71                         (make-method ,form)))
72        form)))
73
74(defgeneric dmc-test-mc.1 (&key k) (:method-combination dmc-test-mc.1))
75
76(defmethod dmc-test-mc.1 dmc-test-mc (&key k)
77  k)
78
79(deftest dmc-test-mc.1
80    (dmc-test-mc.1 :k 1)
81  1)
82
83
84;; Completely DIY -- also taken from SBCL:
85(define-method-combination dmc-test-mc.2 ()
86  ((all-methods *))
87  (do ((methods all-methods (rest methods))
88       (primary nil)
89       (around nil))
90      ((null methods)
91       (let ((primary (nreverse primary))
92             (around (nreverse around)))
93         (if primary
94              (let ((form (if (rest primary)
95                             `(call-method ,(first primary) ,(rest primary))
96                             `(call-method ,(first primary)))))
97                (if around
98                    `(call-method ,(first around) (,@(rest around)
99                                                   (make-method ,form)))
100                    form))
101              `(make-method (error "No primary methods")))))
102    (let* ((method (first methods))
103           (qualifier (first (method-qualifiers method))))
104      (cond
105        ((equal :around qualifier)
106         (push method around))
107        ((null qualifier)
108         (push method primary))))))
109
110(defgeneric dmc-test-mc.2a (val)
111  (:method-combination dmc-test-mc.2))
112
113(defmethod dmc-test-mc.2a ((val number))
114  (+ val (if (next-method-p) (call-next-method) 0)))
115
116(deftest dmc-test-mc.2a
117    (= (dmc-test-mc.2a 13) 13)
118  T)
119
120(defgeneric dmc-test-mc.2b (val)
121  (:method-combination dmc-test-mc.2))
122
123(defmethod dmc-test-mc.2b ((val number))
124  (+ val (if (next-method-p) (call-next-method) 0)))
125
126(defmethod dmc-test-mc.2b :around ((val number))
127  (+ val (if (next-method-p) (call-next-method) 0)))
128
129(deftest dmc-test-mc.2b
130    (= 26 (dmc-test-mc.2b 13))
131  T)
132
133
134;;; Taken from SBCL: error when method sorting is ambiguous
135;;;  with multiple method groups
136
137(define-method-combination dmc-test-mc.3a ()
138  ((around (:around))
139   (primary * :required t))
140  (let ((form (if (rest primary)
141                  `(call-method ,(first primary) ,(rest primary))
142                  `(call-method ,(first primary)))))
143    (if around
144        `(call-method ,(first around) (,@(rest around)
145                                       (make-method ,form)))
146        form)))
147
148(defgeneric dmc-test-mc.3a (val)
149  (:method-combination dmc-test-mc.3a))
150
151(defmethod dmc-test-mc.3a ((val number))
152  (+ val (if (next-method-p) (call-next-method) 0)))
153
154(defmethod dmc-test-mc.3a :around ((val number))
155  (+ val (if (next-method-p) (call-next-method) 0)))
156
157(defmethod dmc-test-mc.3a :somethingelse ((val number))
158  (+ val (if (next-method-p) (call-next-method) 0)))
159
160(deftest dmc-test-mc.3a
161    (multiple-value-bind
162          (value error)
163        (ignore-errors (wam-test-mc.3a 13))
164      (declare (ignore value))
165      (typep error 'error))
166  T)
167
168;;; Taken from SBCL: error when method sorting is ambiguous
169;;;  with a single (non *) method group
170
171
172(define-method-combination dmc-test-mc.3b ()
173  ((methods listp :required t))
174  (if (rest methods)
175      `(call-method ,(first methods) ,(rest methods))
176      `(call-method ,(first methods))))
177
178(defgeneric dmc-test-mc.3b (val)
179  (:method-combination dmc-test-mc.3b))
180
181(defmethod dmc-test-mc.3b :foo ((val number))
182  (+ val (if (next-method-p) (call-next-method) 0)))
183
184(defmethod dmc-test-mc.3b :bar ((val number))
185  (+ val (if (next-method-p) (call-next-method) 0)))
186
187(deftest dmc-test-mc.3b
188    (multiple-value-bind
189          (value error)
190        (ignore-errors (dmc-test-mc.3b 13))
191      (declare (ignore value))
192      (typep error 'error))
193  T)
194
195
196;; Taken from SBCL: test that GF invocation arguments
197;;   are correctly bound using the (:arguments ...) form
198
199(defparameter *dmc-test-4* nil)
200
201(defun object-lock (obj)
202  (push "object-lock" *dmc-test-4*)
203  obj)
204(defun unlock (obj)
205  (push "unlock" *dmc-test-4*)
206  obj)
207(defun lock (obj)
208  (push "lock" *dmc-test-4*)
209  obj)
210
211
212(define-method-combination dmc-test-mc.4 ()
213  ((methods *))
214  (:arguments object)
215  `(unwind-protect
216        (progn (lock (object-lock ,object))
217               ,@(mapcar #'(lambda (method)
218                             `(call-method ,method))
219                         methods))
220     (unlock (object-lock ,object))))
221
222(defgeneric dmc-test.4 (x)
223  (:method-combination dmc-test-mc.4))
224(defmethod dmc-test.4 ((x symbol))
225  (push "primary" *dmc-test-4*))
226(defmethod dmc-test.4 ((x number))
227  (error "foo"))
228
229(deftest dmc-test.4a
230    (progn
231      (setq *dmc-test-4* nil)
232      (values (equal (dmc-test.4 t) '("primary" "lock" "object-lock"))
233              (equal *dmc-test-4* '("unlock" "object-lock"
234                                    "primary" "lock" "object-lock"))))
235  T T)
236
237(deftest dmc-test.4b
238    (progn
239      (setq *dmc-test-4* nil)
240      (ignore-errors (dmc-test.4 1))
241      (equal *dmc-test-4* '("unlock" "object-lock" "lock" "object-lock")))
242  T)
243
244
245;; From SBCL: method combination (long form) with arguments
246
247#-ccl ;; "The value (ABCL.TEST.LISP::EXTRA :EXTRA) is not of the expected type SYMBOL."
248(define-method-combination dmc-test.5 ()
249  ((method-list *))
250  (:arguments arg1 arg2 &aux (extra :extra))
251  `(progn ,@(mapcar (lambda (method) `(call-method ,method)) method-list)))
252
253#-ccl ;; "The value (ABCL.TEST.LISP::EXTRA :EXTRA) is not of the expected type SYMBOL."
254(defgeneric dmc-test-mc.5 (p1 p2 s)
255  (:method-combination dmc-test.5)
256  (:method ((p1 number) (p2 t) s)
257    (vector-push-extend (list 'number p1 p2) s))
258  (:method ((p1 string) (p2 t) s)
259    (vector-push-extend (list 'string p1 p2) s))
260  (:method ((p1 t) (p2 t) s) (vector-push-extend (list t p1 p2) s)))
261
262(deftest dmc-test.5a
263    (let ((v (make-array 0 :adjustable t :fill-pointer t)))
264      (values (dmc-test-mc.5 1 2 v)
265              (equal (aref v 0) '(number 1 2))
266              (equal (aref v 1) '(t 1 2))))
267  1 T T)
268
269
270
271(define-method-combination dmc-test.6 ()
272  ((normal ())
273   (ignored (:ignore :unused)))
274  `(list 'result
275    ,@(mapcar #'(lambda (method) `(call-method ,method)) normal)))
276
277(defgeneric dmc-test-mc.6 (x)
278  (:method-combination dmc-test.6)
279  (:method :ignore ((x number)) (/ 0)))
280
281(deftest dmc-test-mc.6a
282    (multiple-value-bind
283          (value error)
284        (ignore-errors (dmc-test-mc.6 7))
285      (values (null value)
286              (typep error 'error)))
287  T T)
288
289
290(define-method-combination dmc-test.7 ()
291  ((methods *))
292  (:arguments x &rest others)
293  `(progn
294     ,@(mapcar (lambda (method)
295                 `(call-method ,method))
296               methods)
297     (list ,x (length ,others))))
298
299(defgeneric dmc-test-mc.7 (x &rest others)
300  (:method-combination dmc-test.7))
301
302(defmethod dmc-test-mc.7 (x &rest others)
303  (declare (ignore others))
304  nil)
305
306(deftest dmc-test-mc.7a
307    (equal (apply #'dmc-test-mc.7 :foo (list 1 2 3 4 5 6 7 8))
308           '(:foo 8))
309  T)
310
311
312;; Tests for D-M-C with :arguments option
313;; created due to http://abcl.org/trac/ticket/201
314
315(define-method-combination dmc-test-args-with-whole.1 ()
316  ((methods ()))
317  (:arguments &whole whole)
318  `(progn (format nil "using ~a" ,whole)
319          ,@(mapcar (lambda (method) `(call-method ,method))
320                    methods)))
321
322(defgeneric dmc-test-args-with-whole.1 (x)
323  (:method-combination dmc-test-args-with-whole.1)
324  (:method (x) x))
325
326;; This test fails throws an error under #201
327(deftest dmc-test-args-with-whole.1
328    (dmc-test-args-with-whole.1 T)
329  T)
330
331(define-method-combination dmc-test-args-with-whole.2 ()
332  ((methods ()))
333  (:arguments &whole whole &rest rest)
334  `(progn (format nil "using ~a ~a" ,whole ,rest)
335          ,@(mapcar (lambda (method) `(call-method ,method))
336                    methods)))
337
338(defgeneric dmc-test-args-with-whole.2 (x)
339  (:method-combination dmc-test-args-with-whole.2)
340  (:method (x) x))
341
342(deftest dmc-test-args-with-whole.2
343    (dmc-test-args-with-whole.2 T)
344  T)
345
346
347(define-method-combination dmc-test-args-with-whole.3a ()
348  ((methods ()))
349  (:arguments &whole whole &optional opt)
350  `(progn (format nil "using ~a ~a" ,whole ,opt)
351          ,@(mapcar (lambda (method) `(call-method ,method))
352                    methods)))
353
354(defgeneric dmc-test-args-with-whole.3a (x)
355  (:method-combination dmc-test-args-with-whole.3a)
356  (:method (x) x))
357
358(deftest dmc-test-args-with-whole.3a
359    (dmc-test-args-with-whole.3a T)
360  T)
361
362(define-method-combination dmc-test-args-with-whole.3b ()
363  ((methods ()))
364  (:arguments &whole whole &optional opt &key k)
365  `(progn (format nil "using ~a ~a ~a" ,whole ,opt ,k)
366          ,@(mapcar (lambda (method) `(call-method ,method))
367                    methods)))
368
369(defgeneric dmc-test-args-with-whole.3b (x)
370  (:method-combination dmc-test-args-with-whole.3b)
371  (:method (x) x))
372
373(deftest dmc-test-args-with-whole.3b
374    (dmc-test-args-with-whole.3b T)
375  T)
376
377(define-method-combination dmc-test-args-with-whole.3c ()
378  ((methods ()))
379  (:arguments &whole whole &optional opt &rest r)
380  `(progn (format nil "using ~a ~a ~a" ,whole ,opt ,r)
381          ,@(mapcar (lambda (method) `(call-method ,method))
382                    methods)))
383
384(defgeneric dmc-test-args-with-whole.3c (x)
385  (:method-combination dmc-test-args-with-whole.3c)
386  (:method (x) x))
387
388(deftest dmc-test-args-with-whole.3c
389    (dmc-test-args-with-whole.3c T)
390  T)
391
392
393(define-method-combination dmc-test-args-with-whole.3d ()
394  ((methods ()))
395  (:arguments &whole whole &optional opt &rest r &key k)
396  `(progn (format nil "using ~a ~a ~a ~a" ,whole ,opt ,r ,k)
397          ,@(mapcar (lambda (method) `(call-method ,method))
398                    methods)))
399
400(defgeneric dmc-test-args-with-whole.3d (x)
401  (:method-combination dmc-test-args-with-whole.3d)
402  (:method (x) x))
403
404(deftest dmc-test-args-with-whole.3d
405    (dmc-test-args-with-whole.3d T)
406  T)
407
408(define-method-combination dmc-test-args-with-whole.4 ()
409  ((methods ()))
410  (:arguments &whole whole &key k)
411  `(progn (format nil "using ~a ~a" ,whole ,k)
412          ,@(mapcar (lambda (method) `(call-method ,method))
413                    methods)))
414
415(defgeneric dmc-test-args-with-whole.4 (x)
416  (:method-combination dmc-test-args-with-whole.4)
417  (:method (x) x))
418
419(deftest dmc-test-args-with-whole.4
420    (dmc-test-args-with-whole.4 T)
421  T)
422
423(define-method-combination dmc-test-args-with-whole.5 ()
424  ((methods ()))
425  (:arguments &whole whole &aux a)
426  `(progn (format nil "using ~a ~a" ,whole ,a)
427          ,@(mapcar (lambda (method) `(call-method ,method))
428                    methods)))
429
430(defgeneric dmc-test-args-with-whole.5 (x)
431  (:method-combination dmc-test-args-with-whole.5)
432  (:method (x) x))
433
434(deftest dmc-test-args-with-whole.5
435    (dmc-test-args-with-whole.5 T)
436  T)
437
438(define-method-combination dmc-test-args-with-optional.1 ()
439  ((methods ()))
440  (:arguments &optional a)
441  `(progn ,@(mapcar (lambda (method) `(call-method ,method))
442                    methods)
443          ,a))
444
445(defgeneric dmc-test-args-with-optional.1 (x &optional b)
446  (:method-combination dmc-test-args-with-optional.1)
447  (:method (x &optional b) (progn x b)))
448
449(deftest dmc-test-args-with-optional.1a
450    (dmc-test-args-with-optional.1 T)
451  nil)
452
453(deftest dmc-test-args-with-optional.1b
454    (dmc-test-args-with-optional.1 T T)
455  T)
456
457#-ccl ;; "The value (ABCL.TEST.LISP::A :DEFAULT) is not of the expected type SYMBOL."
458(define-method-combination dmc-test-args-with-optional.2 ()
459  ((methods *))
460  (:arguments &optional (a :default))
461  (print `(progn ,@(mapcar (lambda (method) `(call-method ,method))
462                           methods)
463                 ,a)))
464
465#-ccl ;; "The value (ABCL.TEST.LISP::A :DEFAULT) is not of the expected type SYMBOL."
466(defgeneric dmc-test-args-with-optional.2 (x &optional b)
467  (:method-combination dmc-test-args-with-optional.2)
468  (:method (x &optional b) (progn x b)))
469
470(deftest dmc-test-args-with-optional.2a
471    :documentation "TODO"
472    (dmc-test-args-with-optional.2 T)
473  :default)
474
475(deftest dmc-test-args-with-optional.2b
476    :documentation "Describe what the test does here."
477    (dmc-test-args-with-optional.2 T T)
478  T)
479
480#-ccl ;; The value (ABCL.TEST.LISP::A :DEFAULT) is not of the expected type SYMBOL.
481(define-method-combination dmc-test-args-with-optional.3 ()
482  ((methods *))
483  (:arguments &optional (a :default))
484  (print `(progn ,@(mapcar (lambda (method) `(call-method ,method))
485                           methods)
486                 ,a)))
487
488#-ccl ;; The value (ABCL.TEST.LISP::A :DEFAULT) is not of the expected type SYMBOL.
489(defgeneric dmc-test-args-with-optional.3 (x)
490  (:method-combination dmc-test-args-with-optional.3)
491  (:method (x) (progn x)))
492
493#-ccl ;; The value (ABCL.TEST.LISP::A :DEFAULT) is not of the expected type SYMBOL.
494(deftest dmc-test-args-with-optional.3
495    :documentation "TODO"
496    (dmc-test-args-with-optional.3 T)
497  nil)
498
499#-ccl ;; The value (ABCL.TEST.LISP::A :DEFAULT ABCL.TEST.LISP::SUP-P) is not of the expected type SYMBOL.
500(define-method-combination dmc-test-args-with-optional.4 ()
501  ((methods ()))
502  (:arguments &optional (a :default sup-p))
503  `(progn ,@(mapcar (lambda (method) `(call-method ,method))
504                    methods)
505          (values ,a ,sup-p)))
506
507#-ccl
508(defgeneric dmc-test-args-with-optional.4a (x &optional b)
509  (:method-combination dmc-test-args-with-optional.4)
510  (:method (x &optional b) (progn x b)))
511
512#-ccl
513(deftest dmc-test-args-with-optional.4a
514    (dmc-test-args-with-optional.4a T)
515  :default
516  nil)
517
518#-ccl
519(deftest dmc-test-args-with-optional.4b
520    (dmc-test-args-with-optional.4a T T)
521  T
522  T)
523
524#-ccl
525(defgeneric dmc-test-args-with-optional.4c (x)
526  (:method-combination dmc-test-args-with-optional.4)
527  (:method (x) (progn x)))
528
529#-ccl
530(deftest dmc-test-args-with-optional.4c
531    :documentation "TODO"
532    (dmc-test-args-with-optional.4c T)
533  nil
534  nil)
535
536(deftest propagation-init-args
537    ;; https://github.com/armedbear/abcl/issues/80
538
539    ;; just to ensure that the following code runs without errrors
540    ;; allowing the propagation of the initargs
541    (tagbody
542       (defclass a () ())
543       (defclass b (a) ())
544       (make-instance 'b)
545       (defclass a () ((s :accessor s :initarg :s)))
546       (make-instance 'a :s 1)
547       (make-instance 'b :s 1))
548  nil)
549
550(deftest update-instance-for-redefined-class
551    ;; https://github.com/armedbear/abcl/issues/629
552
553    (progn
554      (defclass position () ())
555
556      (defclass x-y-position (position)
557        ((x :initform 0 :accessor position-x :initarg :x)
558         (y :initform 0 :accessor position-y :initarg :y)))
559
560      (defmethod update-instance-for-redefined-class :before
561          ((pos x-y-position) added deleted plist &key)
562        ;; Transform the x-y coordinates to polar coordinates
563        ;; and store into the new slots.
564        (let ((x (getf plist 'x))
565              (y (getf plist 'y)))
566          (setf (position-rho pos) (sqrt (+ (* x x) (* y y)))
567                (position-theta pos) (atan y x))))
568
569      (setf xy1 (make-instance 'x-y-position))
570
571      (defclass x-y-position (position)
572        ((rho :initform 0 :accessor position-rho)
573         (theta :initform 0 :accessor position-theta)))
574
575      (slot-value xy1 'rho))
576
577  0.0)
578
579(deftest propagation-changes-existent-instances
580    ;; https://github.com/armedbear/abcl/issues/630
581    (progn (defclass a () ())
582           (defclass b (a) ())
583           (setf olda (make-instance 'a))
584           (setf oldb (make-instance 'b))
585           (defclass a () ((s :accessor s :initarg :s :initform 1)))
586           (equal (list (slot-value olda 's)
587                        (slot-value oldb 's))
588                  '(1 1)))
589  t)
590
Note: See TracBrowser for help on using the repository browser.