code/irrat: Disable all floating FFI on ARM.
[sbcl/nyef.git] / tests / load.impure.lisp
blobd425672125db73285ebde2af1b5015b51cc053c1
1 ;;;; miscellaneous side-effectful tests of LOAD
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
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
8 ;;;; from CMU CL.
9 ;;;;
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 (defvar *tmp-filename* "load-test.tmp")
16 ;;; Bug reported by Sean Ross: FASL loader set fill pointer to loaded
17 ;;; simple arrays.
19 (defvar *array*)
21 (progn
22 (with-open-file (s *tmp-filename*
23 :direction :output
24 :if-exists :supersede
25 :if-does-not-exist :create)
26 (print '(setq *array* #3a(((1 2) (2 1)) ((3 4) (4 3)))) s))
27 (let (tmp-fasl)
28 (unwind-protect
29 (progn
30 (setq tmp-fasl (compile-file *tmp-filename*))
31 (let ((*array* nil))
32 (load tmp-fasl)
33 (assert (arrayp *array*))
34 (assert (= (array-rank *array*) 3))
35 (assert (not (array-has-fill-pointer-p *array*)))))
36 (when tmp-fasl (delete-file tmp-fasl))
37 (delete-file *tmp-filename*))))
39 ;;; rudimentary external-format test
40 (dolist (ef '(:default :ascii :latin-1 :utf-8))
41 (with-open-file (s *tmp-filename*
42 :direction :output
43 :if-exists :supersede
44 :if-does-not-exist :create)
45 (print '(defun foo (x) (1+ x)) s))
46 (fmakunbound 'foo)
47 (let (tmp-fasl)
48 (unwind-protect
49 (progn
50 (setq tmp-fasl (compile-file *tmp-filename* :external-format ef))
51 (load tmp-fasl)
52 (assert (= (foo 1) 2)))
53 (when tmp-fasl (delete-file tmp-fasl))
54 (delete-file *tmp-filename*))))
56 ;;; As reported by David Tolpin *LOAD-PATHNAME* was not merged.
57 (progn
58 (defparameter *saved-load-pathname* nil)
59 (with-open-file (s *tmp-filename*
60 :direction :output
61 :if-exists :supersede
62 :if-does-not-exist :create)
63 (print '(setq *saved-load-pathname* *load-pathname*) s))
64 (unwind-protect
65 (progn
66 (load *tmp-filename*)
67 (assert (equal (merge-pathnames *tmp-filename*) *saved-load-pathname*)))
68 (delete-file *tmp-filename*)))
70 ;;; Test many, many variations on LOAD.
71 (defparameter *counter* 0)
72 (defparameter *loaded-pathname* nil)
73 (defparameter *loaded-truename* nil)
75 (defparameter *test-program-string* (format nil "~
76 (incf *counter*)
77 (setf *loaded-pathname* *load-pathname*)
78 (setf *loaded-truename* *load-truename*)"))
80 (defmacro load-and-assert (load-argument pathname truename)
81 (let ((before (gensym)))
82 `(let ((,before *counter*)
83 *loaded-pathname* *loaded-truename*)
84 (load ,load-argument :print t :verbose t)
85 (assert (and (= (1+ ,before) *counter*)
86 #-win32 ;kludge
87 (equal ,(if pathname `(merge-pathnames ,pathname))
88 *loaded-pathname*)
89 #-win32 ;kludge
90 (equal ,(if pathname `(merge-pathnames ,truename))
91 *loaded-truename*))))))
93 (defmacro with-test-program (source fasl &body body)
94 (let ((src (gensym))
95 (fsl (gensym)))
96 `(let ((,src ,source)
97 (,fsl ,fasl))
98 (with-open-file (*standard-output* ,src :direction :output
99 :if-exists :supersede)
100 (princ *test-program-string*))
101 (when ,fsl
102 (compile-file ,src :output-file ,fsl))
103 (unwind-protect
104 (progn
105 ,@body)
106 (when (probe-file ,src)
107 (delete-file ,src))
108 (when (and ,fsl (probe-file ,fsl))
109 (delete-file ,fsl))))))
111 ;;; Loading from streams.
113 ;; string-stream
114 (with-input-from-string (s *test-program-string*)
115 (load-and-assert s nil nil))
117 ;; file-stream associated with a source file
118 (let ((source (pathname "load-impure-test.lisp")))
119 (with-test-program source nil
120 (with-open-file (stream source)
121 (load-and-assert stream source source))))
123 ;; file-stream associated with a fasl file
124 (let* ((source (pathname "load-impure-test.lisp"))
125 (fasl (compile-file-pathname source)))
126 (with-test-program source fasl
127 (with-open-file (stream fasl :element-type 'unsigned-byte)
128 (load-and-assert fasl fasl fasl))))
130 ;; Develop a simple Gray stream to test loading from.
131 (defclass load-impure-gray-stream (fundamental-character-input-stream)
132 ((pointer :initform 0 :accessor load-impure-gray-stream-pointer)))
134 (defmethod stream-read-char ((stream load-impure-gray-stream))
135 (with-accessors ((pointer load-impure-gray-stream-pointer)) stream
136 (prog1
137 (if (>= pointer (length *test-program-string*))
138 :eof
139 (char *test-program-string* pointer))
140 (incf pointer))))
142 (defmethod stream-unread-char ((stream load-impure-gray-stream) char)
143 (with-accessors ((pointer load-impure-gray-stream-pointer)) stream
144 (if (<= pointer 0)
145 (error "fibber! you never read from this stream ~S" stream)
146 (decf pointer)))
147 nil)
149 (with-open-stream (stream (make-instance 'load-impure-gray-stream))
150 (load-and-assert stream nil nil))
152 ;;; Loading from things named by pathname designators.
154 ;; Test loading a source file by supplying a complete pathname.
155 (let ((source (pathname "load-impure-test.lisp")))
156 (with-test-program source nil
157 (load-and-assert source source source)))
159 ;; Test loading a source file when supplying a partial pathname.
160 (let ((source (pathname "load-impure-test.lisp"))
161 (partial (pathname "load-impure-test")))
162 (with-test-program source nil
163 (load-and-assert partial source source)))
165 ;; Test loading a source file whose name lacks a type when supplying a
166 ;; partial pathname.
167 (let ((source (make-pathname :type :unspecific
168 :defaults (pathname "load-impure-test")))
169 (partial (pathname "load-impure-test")))
170 (with-test-program source nil
171 (load-and-assert partial partial partial)))
173 ;; Test loading a fasl
174 (let* ((source (pathname "load-impure-test.lisp"))
175 (fasl (compile-file-pathname source)))
176 (with-test-program source fasl
177 (load-and-assert fasl fasl fasl)))
179 ;; Test loading a fasl when supplying a partial pathname.
180 (let* ((source (pathname "load-impure-test.lisp"))
181 (fasl (compile-file-pathname source))
182 (partial (pathname "load-impure-test")))
183 (with-test-program source fasl
184 (load-and-assert partial fasl fasl)))
186 ;; Test loading a fasl whose name lacks a type when supplying a
187 ;; partial pathname.
188 (let* ((source (pathname "load-impure-test.lisp"))
189 (fasl (make-pathname :type :unspecific
190 :defaults (compile-file-pathname source)))
191 (partial (pathname "load-impure-test")))
192 (with-test-program source fasl
193 (load-and-assert partial partial partial)))
195 ;; Test loading a fasl with a strange type
196 (let* ((source (pathname "load-impure-test.lisp"))
197 (fasl (make-pathname :defaults (compile-file-pathname source)
198 :type "compiled-lisp")))
199 (with-test-program source fasl
200 (load-and-assert fasl fasl fasl)))
202 ;;; Errors
204 ;; Ensure that loading a fasl specified with a type checks for the
205 ;; header.
206 (let* ((source (pathname "load-impure-test.lisp"))
207 (fasl (compile-file-pathname source)))
208 (with-test-program source fasl
209 (with-open-file (f fasl :direction :io :if-exists :overwrite
210 :element-type '(unsigned-byte 8))
211 (write-byte 0 f))
212 (handler-case (load fasl)
213 (sb-fasl::fasl-header-missing () :ok))))
215 ;; Ensure that loading a fasl specified without a type checks for the
216 ;; header. Note: this wasn't the behavior in
217 ;; src/code/target-load.lisp v1.40 and earlier (SBCL version 1.0.12.35
218 ;; or so). If target-load.lisp is reverted to that state eventually,
219 ;; this test should be removed (or that definition of LOAD altered).
220 (let* ((source (pathname "load-impure-test.lisp"))
221 (fasl (compile-file-pathname source))
222 (fasl-spec (make-pathname :type nil
223 :defaults (compile-file-pathname source))))
224 (with-test-program source fasl
225 (with-open-file (f fasl :direction :io :if-exists :overwrite
226 :element-type '(unsigned-byte 8))
227 (write-byte 0 f))
228 (handler-case (load fasl-spec)
229 (sb-fasl::fasl-header-missing () :ok))))
231 ;; Ensure that we get an error when the source file is newer than the
232 ;; fasl and the supplied argument is an incomplete pathname.
233 (let* ((source (pathname "load-impure-test.lisp"))
234 (fasl (compile-file-pathname source))
235 (spec (make-pathname :type nil :defaults source)))
236 (with-test-program source fasl
237 (sleep 1)
238 (with-open-file (*standard-output* source :direction :output
239 :if-exists :append)
240 (write-line ";;comment"))
241 (handler-case (load spec)
242 ;; IWBNI the error signalled here were more specific than
243 ;; SIMPLE-ERROR.
244 (error () :|well, we got an error!|))))
246 ;; Ensure that we can invoke the restart SOURCE in the above case.
247 (let* ((source (pathname "load-impure-test.lisp"))
248 (fasl (compile-file-pathname source))
249 (spec (make-pathname :type nil :defaults source)))
250 (with-test-program source fasl
251 (sleep 1)
252 (with-open-file (*standard-output* source :direction :output
253 :if-exists :append)
254 (write-line ";;comment"))
255 (handler-bind ((error (lambda (error)
256 (declare (ignore error))
257 (when (find-restart 'sb-fasl::source)
258 (invoke-restart 'sb-fasl::source)))))
259 (load-and-assert spec source source))))
261 ;; Ensure that we can invoke the restart OBJECT in the above case.
262 (let* ((source (pathname "load-impure-test.lisp"))
263 (fasl (compile-file-pathname source))
264 (spec (make-pathname :type nil :defaults source)))
265 (with-test-program source fasl
266 (sleep 1)
267 (with-open-file (*standard-output* source :direction :output
268 :if-exists :append)
269 (write-line ";;comment"))
270 (handler-bind ((error (lambda (error)
271 (declare (ignore error))
272 (when (find-restart 'sb-fasl::object)
273 (invoke-restart 'sb-fasl::object)))))
274 (load-and-assert spec fasl fasl))))
276 (with-test (:name :bug-332)
277 (flet ((stimulate-sbcl ()
278 (let ((filename
279 (format nil "~A/~A.lisp"
280 (or (posix-getenv "TEST_DIRECTORY")
281 (posix-getenv "TMPDIR")
282 "/tmp")
283 (gensym))))
284 (ensure-directories-exist filename)
285 ;; create a file which redefines a structure incompatibly
286 (with-open-file (f filename :direction :output :if-exists :supersede)
287 (print '(defstruct bug-332 foo) f)
288 (print '(defstruct bug-332 foo bar) f))
289 ;; compile and load the file, then invoke the continue restart on
290 ;; the structure redefinition error
291 (handler-bind ((error (lambda (c) (continue c))))
292 (load (compile-file filename))))))
293 (stimulate-sbcl)
294 (stimulate-sbcl)
295 (stimulate-sbcl)))
297 (defun load-empty-file (type)
298 (let ((pathname (make-pathname :name "load-impure-lisp-empty-temp"
299 :type type)))
300 (unwind-protect
301 (progn
302 (with-open-file (f pathname
303 :if-exists :supersede
304 :direction :output))
305 (handler-case
306 (progn (load pathname) t)
307 (error () nil)))
308 (ignore-errors (delete-file pathname)))))
310 (with-test (:name (load :empty.lisp))
311 (assert (load-empty-file "lisp")))
313 (with-test (:name (load :empty.fasl))
314 (assert (not (load-empty-file "fasl"))))
316 (with-test (:name :parallel-fasl-load)
317 #+sb-thread
318 (let ((lisp #p"parallel-fasl-load-test.lisp")
319 (fasl nil)
320 (ready nil))
321 (unwind-protect
322 (progn
323 (multiple-value-bind (compiled warned failed)
324 (compile-file lisp)
325 (setf fasl compiled)
326 (assert (not warned))
327 (assert (not failed))
328 (labels ((load-loop ()
329 (let* ((*standard-output* (make-broadcast-stream))
330 (*error-output* *standard-output*))
331 (sb-ext:wait-for ready)
332 (handler-case
333 (progn
334 (loop repeat 1000
335 do (load fasl)
336 (test-it))
338 (error (e) e))))
339 (test-it ()
340 (assert (= 1 (one-fun)))
341 (assert (= 2 (two-fun)))
342 (assert (= 42 (symbol-value '*var*)))
343 (assert (= 13 (symbol-value '*quux*)))))
344 (let ((t1 (sb-thread:make-thread #'load-loop))
345 (t2 (sb-thread:make-thread #'load-loop))
346 (t3 (sb-thread:make-thread #'load-loop)))
347 (setf ready t)
348 (let ((r1 (sb-thread:join-thread t1))
349 (r2 (sb-thread:join-thread t2))
350 (r3 (sb-thread:join-thread t3)))
351 (unless (and (eq t r1) (eq t r2) (eq t r3))
352 (error "R1: ~A~2%R2: ~A~2%R2: ~A" r1 r2 r3))
353 ;; These ones cannot be tested while redefinitions are running:
354 ;; adding a method implies REMOVE-METHOD, so a call would be racy.
355 (assert (eq :ok (a-slot (make-instance 'a-class :slot :ok))))
356 (assert (eq 'cons (gen-fun '(foo))))
357 (assert (eq 'a-class (gen-fun (make-instance 'a-class)))))
358 (test-it)))))
359 (when fasl
360 (ignore-errors (delete-file fasl))))))
362 (defvar *pack*)
363 #+sb-simd-pack
364 (with-test (:name :load-simd-pack-int)
365 (with-open-file (s *tmp-filename*
366 :direction :output
367 :if-exists :supersede
368 :if-does-not-exist :create)
369 (print '(setq *pack* (sb-kernel:%make-simd-pack-ub64 2 4)) s))
370 (let (tmp-fasl)
371 (unwind-protect
372 (progn
373 (setq tmp-fasl (compile-file *tmp-filename*))
374 (let ((*pack* nil))
375 (load tmp-fasl)
376 (assert (typep *pack* '(sb-kernel:simd-pack integer)))
377 (assert (= 2 (sb-kernel:%simd-pack-low *pack*)))
378 (assert (= 4 (sb-kernel:%simd-pack-high *pack*)))))
379 (when tmp-fasl (delete-file tmp-fasl))
380 (delete-file *tmp-filename*))))
382 #+sb-simd-pack
383 (with-test (:name :load-simd-pack-single)
384 (with-open-file (s *tmp-filename*
385 :direction :output
386 :if-exists :supersede
387 :if-does-not-exist :create)
388 (print '(setq *pack* (sb-kernel:%make-simd-pack-single 1f0 2f0 3f0 4f0)) s))
389 (let (tmp-fasl)
390 (unwind-protect
391 (progn
392 (setq tmp-fasl (compile-file *tmp-filename*))
393 (let ((*pack* nil))
394 (load tmp-fasl)
395 (assert (typep *pack* '(sb-kernel:simd-pack single-float)))
396 (assert (equal (multiple-value-list (sb-kernel:%simd-pack-singles *pack*))
397 '(1f0 2f0 3f0 4f0)))))
398 (when tmp-fasl (delete-file tmp-fasl))
399 (delete-file *tmp-filename*))))
401 #+sb-simd-pack
402 (with-test (:name :load-simd-pack-double)
403 (with-open-file (s *tmp-filename*
404 :direction :output
405 :if-exists :supersede
406 :if-does-not-exist :create)
407 (print '(setq *pack* (sb-kernel:%make-simd-pack-double 1d0 2d0)) s))
408 (let (tmp-fasl)
409 (unwind-protect
410 (progn
411 (setq tmp-fasl (compile-file *tmp-filename*))
412 (let ((*pack* nil))
413 (load tmp-fasl)
414 (assert (typep *pack* '(sb-kernel:simd-pack double-float)))
415 (assert (equal (multiple-value-list (sb-kernel:%simd-pack-doubles *pack*))
416 '(1d0 2d0)))))
417 (when tmp-fasl (delete-file tmp-fasl))
418 (delete-file *tmp-filename*))))
420 ;; Check that ':load print' on a fasl has some non-null effect
421 (with-test (:name :fasloader-print)
422 (with-open-file (stream *tmp-filename*
423 :direction :output :if-exists :supersede)
424 (dolist (form '((defmacro some-fancy-macro (x) `(car ,x))
425 (defvar *some-var* () nil)
426 (deftype my-favorite-type () '(integer -1 8))
427 (defun fred (x) (- x))
428 (push (some-fancy-macro '(a . b)) *some-var*)))
429 (write form :stream stream)))
430 (let* ((s (make-string-output-stream))
431 (output (compile-file *tmp-filename*)))
432 (let ((*standard-output* s))
433 (load output :print t))
434 (delete-file output)
435 (assert (string= (get-output-stream-string s)
436 ";; SOME-FANCY-MACRO
437 ;; *SOME-VAR*
438 ;; MY-FAVORITE-TYPE
439 ;; NIL
440 ;; FRED
441 ;; (A)"))
442 (delete-file *tmp-filename*)))
444 (with-test (:name :load-reader-error)
445 (unwind-protect
446 (block result
447 (with-open-file (f *tmp-filename* :direction :output
448 :if-does-not-exist :create :if-exists :supersede)
449 (write-string "(defun fool () (nosuchpackage: " f))
450 (handler-bind
451 ((condition
452 (lambda (e)
453 (if (eql (search "READ error during LOAD:"
454 (write-to-string e :escape nil))
456 (return-from result t)
457 (error "Unexpectedly erred: ~S" e)))))
458 (load *tmp-filename* :verbose nil)))
459 (delete-file *tmp-filename*))
460 ;; Not really a test of the bugfix, but a reminder that asdf-dependency-grovel
461 ;; uses this internal macro and that we should endeavor not to break the syntax.
462 (macroexpand '(sb-c::do-forms-from-info
463 ((myform myindex) my-source-info) (something))))