1 ;;;; miscellaneous tests of package-related stuff
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 (defun set-bad-package (x)
15 (declare (optimize (safety 0)))
18 ;; When interpreting, the error occurs in SET-BAD-PACKAGE,
19 ;; not at the INTERN call.
20 (with-test (:name
:set-bad-package
:skipped-on
:interpreter
)
21 (set-bad-package :cl-user
)
22 (assert-error (intern "FRED") type-error
))
24 ;;; Expect an error about the nickname not being a string designator,
25 ;;; not about the nickname being taken by another package.
26 (with-test (:name
:nickname-is-string-designator
)
27 (let ((errmsg (handler-case (make-package "X" :nicknames
(list (find-package "CL")))
28 (error (c) (princ-to-string c
)))))
29 (assert (search "does not designate a string" errmsg
))))
31 (with-test (:name
:packages-sanely-nicknamed
)
32 (dolist (p (list-all-packages))
33 (let* ((nicks (package-nicknames p
))
34 (check (remove-duplicates nicks
:test
'string
=)))
35 (assert (= (length check
) (length nicks
))))))
38 (defvar *foo
* (find-package (coerce "FOO" 'base-string
)))
39 (rename-package "FOO" (make-array 0 :element-type nil
))
40 (assert (eq *foo
* (find-package "")))
41 (assert (delete-package ""))
44 (defvar *baz
* (rename-package "BAR" "BAZ"))
45 (assert (eq *baz
* (find-package "BAZ")))
46 (assert (delete-package *baz
*))
50 (package-error (c) (princ c
))
51 (:no-error
(&rest args
) (error "(EXPORT :FOO) returned ~S" args
)))
54 (assert (shadow #\a :foo
))
56 (defpackage :PACKAGE-DESIGNATOR-1
(:use
#.
(find-package :cl
)))
58 (defpackage :PACKAGE-DESIGNATOR-2
59 (:import-from
#.
(find-package :cl
) "+"))
61 (defpackage "EXAMPLE-INDIRECT"
62 (:import-from
"CL" "+"))
64 (defpackage "EXAMPLE-PACKAGE"
66 (:shadowing-import-from
"CL" "CAAR")
68 (:import-from
"CL" "CDR")
69 (:import-from
"EXAMPLE-INDIRECT" "+")
70 (:export
"CAR" "CDR" "EXAMPLE"))
72 (flet ((check-symbol (name expected-status expected-home-name
)
73 (multiple-value-bind (symbol status
)
74 (find-symbol name
"EXAMPLE-PACKAGE")
75 (let ((home (symbol-package symbol
))
76 (expected-home (find-package expected-home-name
)))
77 (assert (eql home expected-home
))
78 (assert (eql status expected-status
))))))
79 (check-symbol "CAR" :external
"EXAMPLE-PACKAGE")
80 (check-symbol "CDR" :external
"CL")
81 (check-symbol "EXAMPLE" :external
"EXAMPLE-PACKAGE")
82 (check-symbol "CAAR" :internal
"CL")
83 (check-symbol "+" :internal
"CL")
84 (check-symbol "CDDR" nil
"CL"))
86 (defpackage "TEST-ORIGINAL" (:nicknames
"A-NICKNAME"))
88 (assert-error (defpackage "A-NICKNAME"))
90 (assert (eql (find-package "A-NICKNAME")
91 (find-package "TEST-ORIGINAL")))
94 (defun sym (package name
)
95 (let ((package (or (find-package package
) package
)))
96 (multiple-value-bind (symbol status
)
97 (find-symbol name package
)
99 (package name symbol status
)
100 "No symbol with name ~A in ~S." name package symbol status
)
101 (values symbol status
))))
103 (defmacro with-name-conflict-resolution
((symbol &key restarted
)
105 "Resolves potential name conflict condition arising from FORM.
107 The conflict is resolved in favour of SYMBOL, a form which must
108 evaluate to a symbol.
110 If RESTARTED is a symbol, it is bound for the BODY forms and set to T
111 if a restart was invoked."
112 (check-type restarted symbol
"a binding name")
113 (let ((%symbol
(copy-symbol 'symbol
)))
114 `(let (,@(when restarted
`((,restarted
)))
117 ((sb-ext:name-conflict
119 ,@(when restarted
`((setf ,restarted t
)))
120 (assert (member ,%symbol
(sb-ext:name-conflict-symbols condition
)))
121 (invoke-restart 'sb-ext
:resolve-conflict
,%symbol
))))
125 (defmacro with-packages
(specs &body forms
)
126 (let ((names (mapcar #'car specs
)))
129 (delete-packages ',names
)
130 ,@(mapcar (lambda (spec)
131 `(defpackage ,@spec
))
134 (delete-packages ',names
))))
136 (defun delete-packages (names)
138 (ignore-errors (delete-package p
))))
143 (with-test (:name
:use-package
.1)
144 (with-packages (("FOO" (:export
"SYM"))
145 ("BAR" (:export
"SYM"))
147 (with-name-conflict-resolution ((sym "BAR" "SYM") :restarted restartedp
)
148 (use-package '("FOO" "BAR") "BAZ")
150 (is (eq (sym "BAR" "SYM")
151 (sym "BAZ" "SYM"))))))
153 (with-test (:name
:use-package
.2)
154 (with-packages (("FOO" (:export
"SYM"))
155 ("BAZ" (:use
) (:intern
"SYM")))
156 (with-name-conflict-resolution ((sym "FOO" "SYM") :restarted restartedp
)
157 (use-package "FOO" "BAZ")
159 (is (eq (sym "FOO" "SYM")
160 (sym "BAZ" "SYM"))))))
162 (with-test (:name
:use-package
.2a
)
163 (with-packages (("FOO" (:export
"SYM"))
164 ("BAZ" (:use
) (:intern
"SYM")))
165 (with-name-conflict-resolution ((sym "BAZ" "SYM") :restarted restartedp
)
166 (use-package "FOO" "BAZ")
168 (is (equal (list (sym "BAZ" "SYM") :internal
)
169 (multiple-value-list (sym "BAZ" "SYM")))))))
171 (with-test (:name
:use-package-conflict-set
:fails-on
:sbcl
)
172 (with-packages (("FOO" (:export
"SYM"))
173 ("QUX" (:export
"SYM"))
174 ("BAR" (:intern
"SYM"))
175 ("BAZ" (:use
) (:import-from
"BAR" "SYM")))
176 (let ((conflict-set))
179 ((sb-ext:name-conflict
181 (setf conflict-set
(copy-list
182 (sb-ext:name-conflict-symbols condition
)))
184 (use-package '("FOO" "QUX") "BAZ")))
186 (sort conflict-set
#'string
<
187 :key
(lambda (symbol)
188 (package-name (symbol-package symbol
)))))
189 (is (equal (list (sym "BAR" "SYM") (sym "FOO" "SYM") (sym "QUX" "SYM"))
193 (with-test (:name
:export
.1)
194 (with-packages (("FOO" (:intern
"SYM"))
195 ("BAR" (:export
"SYM"))
196 ("BAZ" (:use
"FOO" "BAR")))
197 (with-name-conflict-resolution ((sym "FOO" "SYM") :restarted restartedp
)
198 (export (sym "FOO" "SYM") "FOO")
200 (is (eq (sym "FOO" "SYM")
201 (sym "BAZ" "SYM"))))))
203 (with-test (:name
:export
.1a
)
204 (with-packages (("FOO" (:intern
"SYM"))
205 ("BAR" (:export
"SYM"))
206 ("BAZ" (:use
"FOO" "BAR")))
207 (with-name-conflict-resolution ((sym "BAR" "SYM") :restarted restartedp
)
208 (export (sym "FOO" "SYM") "FOO")
210 (is (eq (sym "BAR" "SYM")
211 (sym "BAZ" "SYM"))))))
213 (with-test (:name
:export.ensure-exported
)
214 (with-packages (("FOO" (:intern
"SYM"))
215 ("BAR" (:export
"SYM"))
216 ("BAZ" (:use
"FOO" "BAR") (:IMPORT-FROM
"BAR" "SYM")))
217 (with-name-conflict-resolution ((sym "FOO" "SYM") :restarted restartedp
)
218 (export (sym "FOO" "SYM") "FOO")
220 (is (equal (list (sym "FOO" "SYM") :external
)
221 (multiple-value-list (sym "FOO" "SYM"))))
222 (is (eq (sym "FOO" "SYM")
223 (sym "BAZ" "SYM"))))))
225 (with-test (:name
:export
.3.intern
)
226 (with-packages (("FOO" (:intern
"SYM"))
227 ("BAZ" (:use
"FOO") (:intern
"SYM")))
228 (with-name-conflict-resolution ((sym "FOO" "SYM") :restarted restartedp
)
229 (export (sym "FOO" "SYM") "FOO")
231 (is (eq (sym "FOO" "SYM")
232 (sym "BAZ" "SYM"))))))
234 (with-test (:name
:export
.3a.intern
)
235 (with-packages (("FOO" (:intern
"SYM"))
236 ("BAZ" (:use
"FOO") (:intern
"SYM")))
237 (with-name-conflict-resolution ((sym "BAZ" "SYM") :restarted restartedp
)
238 (export (sym "FOO" "SYM") "FOO")
240 (is (equal (list (sym "BAZ" "SYM") :internal
)
241 (multiple-value-list (sym "BAZ" "SYM")))))))
244 (with-test (:name
:import-nil
.1)
245 (with-packages (("FOO" (:use
) (:intern
"NIL"))
246 ("BAZ" (:use
) (:intern
"NIL")))
247 (with-name-conflict-resolution ((sym "FOO" "NIL") :restarted restartedp
)
248 (import (list (sym "FOO" "NIL")) "BAZ")
250 (is (eq (sym "FOO" "NIL")
251 (sym "BAZ" "NIL"))))))
253 (with-test (:name
:import-nil
.2)
254 (with-packages (("BAZ" (:use
) (:intern
"NIL")))
255 (with-name-conflict-resolution ('CL
:NIL
:restarted restartedp
)
256 (import '(CL:NIL
) "BAZ")
259 (sym "BAZ" "NIL"))))))
261 (with-test (:name
:import-single-conflict
:fails-on
:sbcl
)
262 (with-packages (("FOO" (:export
"NIL"))
263 ("BAR" (:export
"NIL"))
265 (let ((conflict-sets '()))
267 ((sb-ext:name-conflict
269 (push (copy-list (sb-ext:name-conflict-symbols condition
))
271 (invoke-restart 'sb-ext
:resolve-conflict
'CL
:NIL
))))
272 (import (list 'CL
:NIL
(sym "FOO" "NIL") (sym "BAR" "NIL")) "BAZ"))
273 (is (eql 1 (length conflict-sets
)))
274 (is (eql 3 (length (first conflict-sets
)))))))
276 ;;; Make sure that resolving a name-conflict in IMPORT doesn't leave
277 ;;; multiple symbols of the same name in the package (this particular
278 ;;; scenario found in 1.0.38.9, but clearly a longstanding issue).
279 (with-test (:name
:import-conflict-resolution
)
280 (with-packages (("FOO" (:export
"NIL"))
282 (with-name-conflict-resolution ((sym "FOO" "NIL"))
283 (import (list 'CL
:NIL
(sym "FOO" "NIL")) "BAR"))
284 (do-symbols (sym "BAR")
285 (assert (eq sym
(sym "FOO" "NIL"))))))
288 (with-test (:name
:unintern
.1)
289 (with-packages (("FOO" (:export
"SYM"))
290 ("BAR" (:export
"SYM"))
291 ("BAZ" (:use
"FOO" "BAR") (:shadow
"SYM")))
292 (with-name-conflict-resolution ((sym "FOO" "SYM") :restarted restartedp
)
293 (unintern (sym "BAZ" "SYM") "BAZ")
295 (is (eq (sym "FOO" "SYM")
296 (sym "BAZ" "SYM"))))))
298 (with-test (:name
:unintern
.2)
299 (with-packages (("FOO" (:intern
"SYM")))
300 (unintern :sym
"FOO")
301 (assert (find-symbol "SYM" "FOO"))))
303 ;;; WITH-PACKAGE-ITERATOR error signalling had problems
304 (with-test (:name
:with-package-iterator.error
)
308 (eval '(with-package-iterator (sym :cl-user
:foo
)
311 ((and simple-condition program-error
) (c)
312 (assert (equal (list :foo
) (simple-condition-format-arguments c
)))
315 ;; X3J13 writeup HASH-TABLE-PACKAGE-GENERATORS says
316 ;; "An argument of NIL is treated as an empty list of packages."
317 ;; This used to fail with "NIL does not name a package"
318 (with-test (:name
:with-package-iterator-nil-list
)
319 (with-package-iterator (iter '() :internal
)
320 (assert (null (iter)))))
322 ;;; MAKE-PACKAGE error in another thread blocking FIND-PACKAGE & FIND-SYMBOL
323 (with-test (:name
:bug-511072
:skipped-on
'(not :sb-thread
))
324 (let* ((p (make-package :bug-511072
))
325 (sem1 (sb-thread:make-semaphore
))
326 (sem2 (sb-thread:make-semaphore
))
327 (t2 (make-join-thread (lambda ()
328 (handler-bind ((error (lambda (c)
329 (sb-thread:signal-semaphore sem1
)
330 (sb-thread:wait-on-semaphore sem2
)
332 (make-package :bug-511072
))))))
333 (declare (ignore p t2
))
334 (sb-thread:wait-on-semaphore sem1
)
336 (assert (eq 'cons
(read-from-string "CL:CONS"))))
337 (sb-thread:signal-semaphore sem2
)))
339 (defmacro handling
((condition restart-name
) form
)
340 `(handler-bind ((,condition
(lambda (c)
342 (invoke-restart ',restart-name
))))
346 (with-test (:name
:quick-name-conflict-resolution-import
)
350 (setf p1
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-IMPORT.1")
351 p2
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-IMPORT.2"))
353 (handling (name-conflict sb-impl
::dont-import-it
)
354 (import (intern "FOO" p2
) p1
))
355 (assert (not (eq (intern "FOO" p1
) (intern "FOO" p2
))))
356 (handling (name-conflict sb-impl
::shadowing-import-it
)
357 (import (intern "FOO" p2
) p1
))
358 (assert (eq (intern "FOO" p1
) (intern "FOO" p2
))))
359 (when p1
(delete-package p1
))
360 (when p2
(delete-package p2
)))))
362 (with-test (:name
:quick-name-conflict-resolution-export
.1)
366 (setf p1
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-EXPORT.1a")
367 p2
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-EXPORT.2a"))
370 (handling (name-conflict sb-impl
::keep-old
)
371 (export (intern "FOO" p2
) p2
))
372 (assert (not (eq (intern "FOO" p1
) (intern "FOO" p2
)))))
373 (when p1
(delete-package p1
))
374 (when p2
(delete-package p2
)))))
376 (with-test (:name
:quick-name-conflict-resolution-export
.2)
380 (setf p1
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-EXPORT.1b")
381 p2
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-EXPORT.2b"))
384 (handling (name-conflict sb-impl
::take-new
)
385 (export (intern "FOO" p2
) p2
))
386 (assert (eq (intern "FOO" p1
) (intern "FOO" p2
))))
387 (when p1
(delete-package p1
))
388 (when p2
(delete-package p2
)))))
390 (with-test (:name
:quick-name-conflict-resolution-use-package
.1)
394 (setf p1
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-USE-PACKAGE.1a")
395 p2
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-USE-PACKAGE.2a"))
398 (export (intern "FOO" p2
) p2
)
399 (export (intern "BAR" p2
) p2
)
400 (handling (name-conflict sb-impl
::keep-old
)
402 (assert (not (eq (intern "FOO" p1
) (intern "FOO" p2
))))
403 (assert (not (eq (intern "BAR" p1
) (intern "BAR" p2
)))))
404 (when p1
(delete-package p1
))
405 (when p2
(delete-package p2
)))))
407 (with-test (:name
:quick-name-conflict-resolution-use-package
.2)
411 (setf p1
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-USE-PACKAGE.1b")
412 p2
(make-package "QUICK-NAME-CONFLICT-RESOLUTION-USE-PACKAGE.2b"))
415 (export (intern "FOO" p2
) p2
)
416 (export (intern "BAR" p2
) p2
)
417 (handling (name-conflict sb-impl
::take-new
)
419 (assert (eq (intern "FOO" p1
) (intern "FOO" p2
)))
420 (assert (eq (intern "BAR" p1
) (intern "BAR" p2
))))
421 (when p1
(delete-package p1
))
422 (when p2
(delete-package p2
)))))
424 (with-test (:name
(:package-at-variance-restarts
:shadow
))
426 (*on-package-variance
* '(:error t
)))
429 (setf p
(eval `(defpackage :package-at-variance-restarts
.1
432 (handling (sb-kernel::package-at-variance-error sb-impl
::keep-them
)
433 (eval `(defpackage :package-at-variance-restarts
.1
435 (assert (not (eq 'cl
:cons
(intern "CONS" p
))))
436 (handling (sb-kernel::package-at-variance-error sb-impl
::drop-them
)
437 (eval `(defpackage :package-at-variance-restarts
.1
439 (assert (eq 'cl
:cons
(intern "CONS" p
))))
440 (when p
(delete-package p
)))))
442 (with-test (:name
(:package-at-variance-restarts
:use
))
444 (*on-package-variance
* '(:error t
)))
447 (setf p
(eval `(defpackage :package-at-variance-restarts
.2
449 (handling (sb-kernel::package-at-variance-error sb-impl
::keep-them
)
450 (eval `(defpackage :package-at-variance-restarts
.2
452 (assert (eq 'cl
:cons
(intern "CONS" p
)))
453 (handling (sb-kernel::package-at-variance-error sb-impl
::drop-them
)
454 (eval `(defpackage :package-at-variance-restarts
.2
456 (assert (not (eq 'cl
:cons
(intern "CONS" p
)))))
457 (when p
(delete-package p
)))))
459 (with-test (:name
(:package-at-variance-restarts
:export
))
461 (*on-package-variance
* '(:error t
)))
464 (setf p
(eval `(defpackage :package-at-variance-restarts
.4
466 (handling (sb-kernel::package-at-variance-error sb-impl
::keep-them
)
467 (eval `(defpackage :package-at-variance-restarts
.4)))
468 (assert (eq :external
(nth-value 1 (find-symbol "FOO" p
))))
469 (handling (sb-kernel::package-at-variance-error sb-impl
::drop-them
)
470 (eval `(defpackage :package-at-variance-restarts
.4)))
471 (assert (eq :internal
(nth-value 1 (find-symbol "FOO" p
)))))
472 (when p
(delete-package p
)))))
474 (with-test (:name
(:package-at-variance-restarts
:implement
))
476 (*on-package-variance
* '(:error t
)))
479 (setf p
(eval `(defpackage :package-at-variance-restarts
.5
480 (:implement
:sb-int
))))
481 (handling (sb-kernel::package-at-variance-error sb-impl
::keep-them
)
482 (eval `(defpackage :package-at-variance-restarts
.5)))
483 (assert (member p
(package-implemented-by-list :sb-int
)))
484 (handling (sb-kernel::package-at-variance-error sb-impl
::drop-them
)
485 (eval `(defpackage :package-at-variance-restarts
.5)))
486 (assert (not (member p
(package-implemented-by-list :sb-int
)))))
487 (when p
(delete-package p
)))))
489 (with-test (:name
(:delete-package
:implementation-package
))
493 (setf p1
(make-package "DELETE-PACKAGE/IMPLEMENTATION-PACKAGE.1")
494 p2
(make-package "DELETE-PACKAGE/IMPLEMENTATION-PACKAGE.2"))
495 (add-implementation-package p2 p1
)
496 (assert (= 1 (length (package-implemented-by-list p1
))))
498 (assert (= 0 (length (package-implemented-by-list p1
)))))
499 (when p1
(delete-package p1
))
500 (when p2
(delete-package p2
)))))
502 (with-test (:name
(:delete-package
:implementated-package
))
506 (setf p1
(make-package "DELETE-PACKAGE/IMPLEMENTED-PACKAGE.1")
507 p2
(make-package "DELETE-PACKAGE/IMPLEMENTED-PACKAGE.2"))
508 (add-implementation-package p2 p1
)
509 (assert (= 1 (length (package-implements-list p2
))))
511 (assert (= 0 (length (package-implements-list p2
)))))
512 (when p1
(delete-package p1
))
513 (when p2
(delete-package p2
)))))
515 (with-test (:name
:package-local-nicknames
)
517 (without-package-locks
518 (when (find-package :package-local-nicknames-test-1
)
519 (delete-package :package-local-nicknames-test-1
))
520 (when (find-package :package-local-nicknames-test-2
)
521 (delete-package :package-local-nicknames-test-2
)))
522 (eval `(defpackage :package-local-nicknames-test-1
523 (:local-nicknames
(:l
:cl
) (:sb
:sb-ext
))))
524 (eval `(defpackage :package-local-nicknames-test-2
527 (let ((alist (package-local-nicknames :package-local-nicknames-test-1
)))
528 (assert (equal (cons "L" (find-package "CL")) (assoc "L" alist
:test
'string
=)))
529 (assert (equal (cons "SB" (find-package "SB-EXT")) (assoc "SB" alist
:test
'string
=)))
530 (assert (eql 2 (length alist
))))
532 (let ((*package
* (find-package :package-local-nicknames-test-1
)))
533 (let ((cons0 (read-from-string "L:CONS"))
534 (exit0 (read-from-string "SB:EXIT"))
535 (cons1 (find-symbol "CONS" :l
))
536 (exit1 (find-symbol "EXIT" :sb
))
537 (cl (find-package :l
))
538 (sb (find-package :sb
)))
539 (assert (eq 'cons cons0
))
540 (assert (eq 'cons cons1
))
541 (assert (equal "L:CONS" (prin1-to-string cons0
)))
542 (assert (eq 'sb-ext
:exit exit0
))
543 (assert (eq 'sb-ext
:exit exit1
))
544 (assert (equal "SB:EXIT" (prin1-to-string exit0
)))
545 (assert (eq cl
(find-package :common-lisp
)))
546 (assert (eq sb
(find-package :sb-ext
)))))
547 ;; Can't add same name twice for different global names.
550 (add-package-local-nickname :l
:package-local-nicknames-test-2
551 :package-local-nicknames-test-1
)
554 ;; But same name twice is OK.
555 (add-package-local-nickname :l
:cl
:package-local-nicknames-test-1
)
557 (assert (remove-package-local-nickname :l
:package-local-nicknames-test-1
))
558 (let ((*package
* (find-package :package-local-nicknames-test-1
)))
559 (let ((exit0 (read-from-string "SB:EXIT"))
560 (exit1 (find-symbol "EXIT" :sb
))
561 (sb (find-package :sb
)))
562 (assert (eq 'sb-ext
:exit exit0
))
563 (assert (eq 'sb-ext
:exit exit1
))
564 (assert (equal "SB:EXIT" (prin1-to-string exit0
)))
565 (assert (eq sb
(find-package :sb-ext
)))
566 (assert (not (find-package :l
)))))
567 ;; Adding back as another package.
568 (assert (eq (find-package :package-local-nicknames-test-1
)
569 (add-package-local-nickname :l
:package-local-nicknames-test-2
570 :package-local-nicknames-test-1
)))
571 (let ((*package
* (find-package :package-local-nicknames-test-1
)))
572 (let ((cons0 (read-from-string "L:CONS"))
573 (exit0 (read-from-string "SB:EXIT"))
574 (cons1 (find-symbol "CONS" :l
))
575 (exit1 (find-symbol "EXIT" :sb
))
576 (cl (find-package :l
))
577 (sb (find-package :sb
)))
578 (assert (eq cons0 cons1
))
579 (assert (not (eq 'cons cons0
)))
580 (assert (eq (find-symbol "CONS" :package-local-nicknames-test-2
)
582 (assert (equal "L:CONS" (prin1-to-string cons0
)))
583 (assert (eq 'sb-ext
:exit exit0
))
584 (assert (eq 'sb-ext
:exit exit1
))
585 (assert (equal "SB:EXIT" (prin1-to-string exit0
)))
586 (assert (eq cl
(find-package :package-local-nicknames-test-2
)))
587 (assert (eq sb
(find-package :sb-ext
)))))
588 ;; Interaction with package locks.
589 (lock-package :package-local-nicknames-test-1
)
590 (assert (eq :package-oopsie
592 (add-package-local-nickname :c
:sb-c
:package-local-nicknames-test-1
)
593 (package-lock-violation ()
595 (assert (eq :package-oopsie
597 (remove-package-local-nickname :l
:package-local-nicknames-test-1
)
598 (package-lock-violation ()
600 (unlock-package :package-local-nicknames-test-1
)
601 (add-package-local-nickname :c
:sb-c
:package-local-nicknames-test-1
)
602 (remove-package-local-nickname :l
:package-local-nicknames-test-1
))
604 (defmacro with-tmp-packages
(bindings &body body
)
605 `(let ,(mapcar #'car bindings
)
608 (setf ,@(apply #'append bindings
))
610 ,@(mapcar (lambda (p)
611 `(when ,p
(delete-package ,p
)))
612 (mapcar #'car bindings
)))))
614 (with-test (:name
(:delete-package
:locally-nicknames-others
))
615 (with-tmp-packages ((p1 (make-package "LOCALLY-NICKNAMES-OTHERS"))
616 (p2 (make-package "LOCALLY-NICKNAMED-BY-OTHERS")))
617 (add-package-local-nickname :foo p2 p1
)
618 (assert (equal (list p1
) (package-locally-nicknamed-by-list p2
)))
620 (assert (not (package-locally-nicknamed-by-list p2
)))))
622 (with-test (:name
(:delete-package
:locally-nicknamed-by-others
))
623 (with-tmp-packages ((p1 (make-package "LOCALLY-NICKNAMES-OTHERS"))
624 (p2 (make-package "LOCALLY-NICKNAMED-BY-OTHERS")))
625 (add-package-local-nickname :foo p2 p1
)
626 (assert (package-local-nicknames p1
))
628 (assert (not (package-local-nicknames p1
)))))
630 (with-test (:name
:own-name-as-local-nickname
)
631 (with-tmp-packages ((p1 (make-package "OWN-NAME-AS-NICKNAME1"))
632 (p2 (make-package "OWN-NAME-AS-NICKNAME2")))
635 (add-package-local-nickname :own-name-as-nickname1 p2 p1
)
638 (handler-bind ((error #'continue
))
639 (add-package-local-nickname :own-name-as-nickname1 p2 p1
))
640 (assert (eq (intern "FOO" p2
)
641 (let ((*package
* p1
))
642 (intern "FOO" :own-name-as-nickname1
))))))
644 (with-test (:name
:own-nickname-as-local-nickname
)
645 (with-tmp-packages ((p1 (make-package "OWN-NICKNAME-AS-NICKNAME1"
646 :nicknames
'("OWN-NICKNAME")))
647 (p2 (make-package "OWN-NICKNAME-AS-NICKNAME2")))
650 (add-package-local-nickname :own-nickname p2 p1
)
653 (handler-bind ((error #'continue
))
654 (add-package-local-nickname :own-nickname p2 p1
))
655 (assert (eq (intern "FOO" p2
)
656 (let ((*package
* p1
))
657 (intern "FOO" :own-nickname
))))))
659 (with-test (:name
:delete-package-restart
)
663 ((sb-kernel:simple-package-error
667 (delete-package (gensym)))))
669 (assert (not result
))))
671 ;; WITH-PACKAGE-ITERATOR isn't well-exercised by tests (though LOOP uses it)
672 ;; so here's a basic correctness test with some complications involving
673 ;; shadowing symbols.
674 (make-package "P1" :use
'("SB-FORMAT"))
676 (export 'p1
::foo
'p1
)
677 (shadow "FORMAT-ERROR" 'p1
)
678 (make-package "A" :use
'("SB-FORMAT" "P1" "P2"))
679 (shadow '("PROG2" "FOO") 'a
)
681 (export 'p2
::(foo bar baz
) 'p2
)
682 (export 'a
::goodfun
'a
)
684 (with-test (:name
:with-package-iterator
)
685 (let ((tests '((:internal
) (:external
) (:inherited
)
686 (:internal
:inherited
)
687 (:internal
:external
)
688 (:external
:inherited
)
689 (:internal
:external
:inherited
)))
691 '(;; symbols visible in A
692 (a::prog2
:internal
"A")
693 (a::foo
:internal
"A")
694 (a:goodfun
:external
"A")
695 (p2:bar
:inherited
"A")
696 (p2:baz
:inherited
"A")
697 (sb-format:%compiler-walk-format-string
:inherited
"A")
698 (sb-format:format-error
:inherited
"A")
700 (p1:foo
:external
"P1")
701 (p1::format-error
:internal
"P1")
702 (sb-format:%compiler-walk-format-string
:inherited
"P1")
704 (p2::blah
:internal
"P2")
705 (p2:foo
:external
"P2")
706 (p2:bar
:external
"P2")
707 (p2:baz
:external
"P2"))))
708 ;; Compile a new function to test each combination of
709 ;; accessibility-kind since the macro doesn't eval them.
710 (dolist (access tests
)
711 ; (print `(testing ,access))
715 (with-package-iterator (iter '(p1 a p2
) ,@access
)
718 (multiple-value-bind (foundp sym access pkg
) (iter)
720 (push (list sym access
(package-name pkg
)) res
)
723 (let ((answer (funcall f
))
724 (expect (remove-if-not (lambda (x) (member (second x
) access
))
726 ;; exactly as many results as expected
727 (assert (equal (length answer
) (length expect
)))
728 ;; each result is right
729 (assert (equal (length (intersection answer expect
:test
#'equal
))
730 (length expect
))))))))
732 ;; Assert that changes in size of a package-hashtable's symbol vector
733 ;; do not cause WITH-PACKAGE-ITERATOR to crash. The vector shouldn't grow,
734 ;; because it is not permitted to INTERN new symbols, but it can shrink
735 ;; because it is expressly permitted to UNINTERN the current symbol.
736 ;; (In fact we allow INTERN, but that's beside the point)
737 (with-test (:name
:with-package-iterator-and-mutation
)
738 (flet ((table-size (pkg)
739 (length (sb-impl::package-hashtable-cells
740 (sb-impl::package-internal-symbols pkg
)))))
741 (let* ((p (make-package (string (gensym))))
742 (initial-table-size (table-size p
))
744 '("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m")))
747 (let ((grown-table-size (table-size p
)))
748 (assert (> grown-table-size initial-table-size
))
750 (with-package-iterator (iter p
:internal
)
751 (loop (multiple-value-bind (foundp sym
) (iter)
757 (assert (= n
(length strings
)))
758 ;; while we're at it, assert that calling the iterator
759 ;; a couple more times returns nothing.
761 (assert (not (iter))))))
762 (let ((shrunk-table-size (table-size p
)))
763 (assert (< shrunk-table-size grown-table-size
)))))))
766 (with-test (:name
:do-symbols-block-scope
)
769 (do-symbols (s (or (find-package "FROB") (return nil
)))
773 (with-test (:name
:export-inaccessible-lookalike
)
776 (export (intern "A" "E2") 'e2
)
777 (multiple-value-bind (answer condition
)
778 (ignore-errors (export (intern "A" "E1") 'e2
))
779 (assert (and (not answer
)
780 (and (typep condition
'sb-kernel
:simple-package-error
)
781 (search "not accessible"
782 (simple-condition-format-control condition
)))))))
784 ;; Concurrent FIND-SYMBOL was adversely affected by package rehash.
785 ;; It's slightly difficult to show that this is fixed, because this
786 ;; test only sometimes failed prior to the fix. Now it never fails though.
787 (with-test (:name
:concurrent-find-symbol
:skipped-on
'(not :sb-thread
))
788 (let ((pkg (make-package (gensym)))
793 (let ((s (string (gensym "FRED"))))
797 (push (sb-thread:make-thread
801 (dotimes (i 10 n-missing
)
803 (unless (find-symbol name pkg
)
804 (incf n-missing
)))))))
807 ;; Interning new symbols can't cause the pre-determined
808 ;; 50 names to transiently disappear.
809 (let ((s (make-string 3))
810 (alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"))
811 (dotimes (i (expt 32 3))
812 (setf (char s
0) (char alphabet
(ldb (byte 5 10) i
))
813 (char s
1) (char alphabet
(ldb (byte 5 5) i
))
814 (char s
2) (char alphabet
(ldb (byte 5 0) i
)))
816 (let ((tot-missing 0))
817 (dolist (thread threads
(assert (zerop tot-missing
)))
818 (incf tot-missing
(sb-thread:join-thread thread
))))))
820 (with-test (:name
:defpackage-multiple-nicknames
)
821 (let* ((name1 (string (gensym)))
822 (name2 (string (gensym)))
823 (names (package-nicknames
824 (eval `(defpackage ,(gensym)
826 (:nicknames
,name2
))))))
832 (list name2 name1
))))))
834 (with-test (:name
(defpackage :local-nicknames
:lock
))
835 (destructuring-bind (name1 name2 name3
)
836 (loop :repeat
3 :collect
(string (gensym)))
837 (let ((package1 (eval `(defpackage ,name1
)))
838 (package2 (eval `(defpackage ,name2
839 (:local-nicknames
(,name3
,name1
))
841 (assert (equal (package-local-nicknames package2
) `((,name3 .
,package1
))))
842 (assert (package-locked-p package2
)))))
844 ;;; Now a possibly useless test on an essentially useless function.
845 ;;; But we may as well get it right - assert that GENTEMP returns
846 ;;; a symbol that definitely did not exist in the specified package
847 ;;; even if multiple threads are calling it simultaneously.
849 ;;; We'll create about 25000 symbols, and mark the ones that were returned
850 ;;; by GENTEMP. Because *GENTEMP-COUNTER* isn't synchronized, but INTERN is,
851 ;;; returning an indicator of whether it created a symbol, it's simple enough
852 ;;; to make GENTEMP not accidentally return a symbol created by someone else.
854 ;;; Use array of fixnums because there're no atomic ops on array of word.
855 ;;; This is either 58000 useful bits or 126000 bits depending on word size.
856 (defglobal *scoreboard
* (make-array 2000))
857 (defglobal *testpkg
* (make-package "A-NICE-PACKAGE"))
859 (defun hammer-on-gentemp (package n-iter
)
861 (let ((index (parse-integer (string (gentemp "T" package
)) :start
1)))
862 ;; Mark this index in the scoreboard, failing if already set.
863 (multiple-value-bind (elt-index bit-index
)
864 (floor index sb-vm
:n-positive-fixnum-bits
)
865 (let ((old (svref *scoreboard
* elt-index
)))
867 (when (logbitp bit-index old
) (return-from hammer-on-gentemp
:fail
))
869 (cas (svref *scoreboard
* elt-index
)
870 old
(logior old
(ash 1 bit-index
)))))
871 (if (eq old actual-old
) (return))
872 (setq old actual-old
))))))))
874 ;; This test would consistently fail when GENTEMP first called FIND-SYMBOL
875 ;; and then INTERN when FIND-SYMBOL said that it found no symbol.
876 (with-test (:name
(gentemp :threadsafety
) :skipped-on
'(not :sb-thread
))
880 (dotimes (i n-threads
)
881 (push (sb-thread:make-thread
#'hammer-on-gentemp
882 :arguments
(list *testpkg
* n-iter
))
884 (let ((results (mapcar #'sb-thread
:join-thread threads
)))
885 (assert (not (find :fail results
))))))
887 ;;; This test is a bit weak in that prior to the fix for what it tests,
888 ;;; it didn't fail often enough to convincingly show that there was a problem.
889 ;;; Nonetheless it did sometimes fail, and now should never fail.
890 (with-test (:name
:concurrent-intern-bad-published-symbol-package
891 ;; No point in wasting time on concurrency bugs otherwise
892 :skipped-on
'(not :sb-thread
))
893 ;; Confirm that the compiler does not know that KEYWORDICATE
894 ;; returns a KEYWORD (so the answer isn't constant-folded)
895 (assert (sb-kernel:type
= (sb-int:info
:function
:type
'sb-int
:keywordicate
)
896 (sb-kernel:find-classoid
'function
)))
897 (let ((sema (sb-thread:make-semaphore
))
899 (dotimes (i 10) ; number of trials
901 (dotimes (i n-threads
)
902 (push (make-join-thread
904 (sb-thread:wait-on-semaphore sema
)
905 (keywordp (sb-int:keywordicate
"BLUB"))))
907 (sb-thread:signal-semaphore sema n-threads
)
909 (dolist (thread threads
)
910 (when (sb-thread:join-thread thread
) (incf count
)))
911 (unintern (sb-int:keywordicate
"BLUB") "KEYWORD")
912 (assert (= count n-threads
)))))))