1 ;;;; Testing CALL-NEXT-METHOD.
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
14 ;;; CALL-NEXT-METHOD arguments are only fully checked on high safety.
15 (declaim (optimize (safety 3)))
19 ;;; It makes sense to cover all permutations of arguments since the
20 ;;; order of calls can affect the construction of the CALL-NEXT-METHOD
23 ;;; Assumes unique elements in SEQUENCE.
24 (defun map-permutations (function sequence
)
25 (labels ((rec (partial-permutation remainder
)
27 (funcall function partial-permutation
)
28 (map nil
(lambda (element)
29 (rec (list* element partial-permutation
)
30 (remove element remainder
)))
34 ;;; RESET-FUNCTION is used to reset the generic function between
35 ;;; permutations so caches are built up from scratch according to the
36 ;;; following call sequence.
37 (defun map-test-case-permutations (reset-function check-function test-cases
)
40 (funcall reset-function
)
41 (map nil
(lambda (arguments-and-expected)
42 (destructuring-bind (arguments expected
) arguments-and-expected
43 (funcall check-function arguments expected
)))
47 ;;; Make sure CALL-NEXT-METHOD calls that result in different sets of
48 ;;; applicable methods signal errors.
50 (defgeneric different-applicable-methods
(thing)
53 (:method
((thing null
))
55 (:method
((thing list
))
56 (list 'list
(call-next-method (rest thing
))))
57 (:method
((thing cons
))
58 (list 'cons
(call-next-method (rest thing
)))))
60 (with-test (:name
(call-next-method :different-applicable-methods
))
61 (map-test-case-permutations
63 (sb-pcl::update-dfun
#'different-applicable-methods
))
64 (lambda (arguments expected
)
66 (apply #'different-applicable-methods arguments
)))
68 (error (assert-error (do-it)))
69 (t (assert (equal (do-it) expected
))))))
70 '((((1 2 3)) (cons (list (t (3)))))
75 ;;; Test calling the next method with non-EQL arguments of the same
78 (defgeneric non-eql-arguments
(x)
82 (list 'number
(call-next-method (1+ x
))))
84 (list 'real
(call-next-method (1+ x
))))
85 (:method
((x integer
))
86 (list 'integer
(call-next-method (1+ x
)))))
88 (with-test (:name
(call-next-method :same-applicable-methods
:non-eql-arguments
))
89 (map-test-case-permutations
91 (sb-pcl::update-dfun
#'non-eql-arguments
))
92 (lambda (arguments expected
)
93 (assert (equal (apply #'non-eql-arguments arguments
) expected
)))
94 '(((1) (integer (real (number (t 4)))))
95 ((1/2) (real (number (t 5/2))))
96 ((#C
(1 2)) (number (t #C
(2 2)))))))
98 ;;; Test EQL specializers which always require a dedicated method in
99 ;;; the CALL-NEXT-METHOD argument checker.
101 (defgeneric eql-specializer
(x)
104 (:method
((x number
))
105 (list 'number
(call-next-method (1+ x
))))
107 (list 'real
(call-next-method (1+ x
))))
108 (:method
((x integer
))
109 (list 'integer
(call-next-method (1+ x
))))
110 (:method
((x (eql 4)))
111 (list 'eql
4 (call-next-method (1+ x
))))
112 (:method
((x (eql 5)))
113 (list 'eql
5 (call-next-method (1+ x
)))))
115 (with-test (:name
(call-next-method :eql-specializer
))
116 (map-test-case-permutations
118 (sb-pcl::update-dfun
#'eql-specializer
))
119 (lambda (arguments expected
)
121 (apply #'eql-specializer arguments
)))
123 (error (assert-error (do-it)))
124 (t (assert (equal (do-it) expected
))))))
125 '(((0) (integer (real (number (t 3)))))
127 ;; ((2) error) ; too slow otherwise (exponential scaling)
131 ((6) (integer (real (number (t 9)))))
132 ((1/2) (real (number (t 5/2))))
133 ((#C
(1 2)) (number (t #C
(2 2))))