0.8.7.36:
[sbcl.git] / contrib / sb-posix / posix-tests.lisp
1 (defpackage "SB-POSIX-TESTS"
2   (:use "COMMON-LISP" "SB-RT"))
3
4 (in-package "SB-POSIX-TESTS")
5
6 (defvar *test-directory*
7   (ensure-directories-exist
8    (merge-pathnames (make-pathname :directory '(:relative "test-lab"))
9                     (make-pathname :directory
10                                    (pathname-directory *load-truename*)))))
11
12 (defvar *current-directory* *default-pathname-defaults*)
13
14 (defvar *this-file* *load-truename*)
15
16 (eval-when (:compile-toplevel :load-toplevel)
17   (defconstant +mode-rwx-all+ (logior sb-posix::s-irusr sb-posix::s-iwusr sb-posix::s-ixusr
18                                       sb-posix::s-irgrp sb-posix::s-iwgrp sb-posix::s-ixgrp
19                                       sb-posix::s-iroth sb-posix::s-iwoth sb-posix::s-ixoth)))
20 \f
21 (deftest chdir.1
22   (sb-posix:chdir *test-directory*)
23   0)
24
25 (deftest chdir.2
26   (sb-posix:chdir (namestring *test-directory*))
27   0)
28
29 (deftest chdir.3
30   (sb-posix:chdir "/")
31   0)
32
33 (deftest chdir.4
34   (sb-posix:chdir #p"/")
35   0)
36
37 (deftest chdir.5
38   (sb-posix:chdir *current-directory*)
39   0)
40
41 (deftest chdir.6
42   (sb-posix:chdir "/../")
43   0)
44
45 (deftest chdir.7
46   (sb-posix:chdir #p"/../")
47   0)
48
49 (deftest chdir.8
50   (sb-posix:chdir (make-pathname :directory '(:absolute :up)))
51   0)
52
53 (deftest chdir.error.1
54   (let ((dne (make-pathname :directory '(:relative "chdir.does-not-exist"))))
55     (handler-case
56         (sb-posix:chdir (merge-pathnames dne *test-directory*))
57       (sb-posix:syscall-error (c)
58         (sb-posix:syscall-errno c))))
59   #.sb-posix::enoent)
60
61 (deftest chdir.error.2
62   (handler-case
63       (sb-posix:chdir *this-file*)
64     (sb-posix:syscall-error (c)
65       (sb-posix:syscall-errno c)))
66   #.sb-posix::enotdir)
67 \f
68 (deftest mkdir.1
69   (let ((dne (make-pathname :directory '(:relative "mkdir.does-not-exist.1"))))
70     (unwind-protect
71          (sb-posix:mkdir (merge-pathnames dne *test-directory*) 0)
72       ;; FIXME: no delete-directory in CL, but using our own operators
73       ;; is probably not ideal
74       (ignore-errors (sb-posix:rmdir (merge-pathnames dne *test-directory*)))))
75   0)
76
77 (deftest mkdir.2
78   (let ((dne (make-pathname :directory '(:relative "mkdir.does-not-exist.2"))))
79     (unwind-protect
80          (sb-posix:mkdir (namestring (merge-pathnames dne *test-directory*)) 0)
81       (ignore-errors (sb-posix:rmdir (merge-pathnames dne *test-directory*)))))
82   0)
83
84 (deftest mkdir.error.1
85   (handler-case
86       (sb-posix:mkdir *test-directory* 0)
87     (sb-posix:syscall-error (c)
88       (sb-posix:syscall-errno c)))
89   #.sb-posix::eexist)
90
91 (deftest mkdir.error.2
92   (handler-case
93       (sb-posix:mkdir "/" 0)
94     (sb-posix:syscall-error (c)
95       (sb-posix:syscall-errno c)))
96   #.sb-posix::eexist)
97
98 (deftest mkdir.error.3
99   (handler-case
100       (sb-posix:mkdir "/almost-certainly-does-not-exist" 0)
101     (sb-posix:syscall-error (c)
102       (sb-posix:syscall-errno c)))
103   #.sb-posix::eacces)
104 \f
105 (deftest rmdir.1
106   (let ((dne (make-pathname :directory '(:relative "rmdir.does-not-exist.1"))))
107     (ensure-directories-exist (merge-pathnames dne *test-directory*))
108     (sb-posix:rmdir (merge-pathnames dne *test-directory*)))
109   0)
110
111 (deftest rmdir.2
112   (let ((dne (make-pathname :directory '(:relative "rmdir.does-not-exist.2"))))
113     (ensure-directories-exist (merge-pathnames dne *test-directory*))
114     (sb-posix:rmdir (namestring (merge-pathnames dne *test-directory*))))
115   0)
116
117 (deftest rmdir.error.1
118   (let ((dne (make-pathname :directory '(:relative "rmdir.dne.error.1"))))
119     (handler-case 
120         (sb-posix:rmdir (merge-pathnames dne *test-directory*))
121       (sb-posix:syscall-error (c)
122         (sb-posix:syscall-errno c))))
123   #.sb-posix::enoent)
124
125 (deftest rmdir.error.2
126   (handler-case
127       (sb-posix:rmdir *this-file*)
128     (sb-posix:syscall-error (c)
129       (sb-posix:syscall-errno c)))
130   #.sb-posix::enotdir)
131
132 #-sunos ; Apparently gives EINVAL on SunOS 8, which doesn't make sense
133 (deftest rmdir.error.3
134   (handler-case
135       (sb-posix:rmdir "/")
136     (sb-posix:syscall-error (c)
137       (sb-posix:syscall-errno c)))
138   #.sb-posix::ebusy)
139
140 (deftest rmdir.error.4
141   (let* ((dir (ensure-directories-exist
142                (merge-pathnames
143                 (make-pathname :directory '(:relative "rmdir.error.4"))
144                 *test-directory*)))
145          (file (make-pathname :name "foo" :defaults dir)))
146     (with-open-file (s file :direction :output)
147       (write "" :stream s))
148     (handler-case
149         (sb-posix:rmdir dir)
150       (sb-posix:syscall-error (c)
151         (delete-file file)
152         (sb-posix:rmdir dir)
153         (let ((errno (sb-posix:syscall-errno c)))
154           ;; documented by POSIX
155           (or (= errno sb-posix::eexist) (= errno sb-posix::enotempty))))))
156   t)
157
158 (deftest rmdir.error.5
159   (let* ((dir (merge-pathnames
160                (make-pathname :directory '(:relative "rmdir.error.5"))
161                *test-directory*))
162          (dir2 (merge-pathnames
163                 (make-pathname :directory '(:relative "unremovable"))
164                 dir)))
165     (sb-posix:mkdir dir +mode-rwx-all+)
166     (sb-posix:mkdir dir2 +mode-rwx-all+)
167     (sb-posix:chmod dir 0)
168     (handler-case
169         (sb-posix:rmdir dir2)
170       (sb-posix:syscall-error (c)
171         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
172         (sb-posix:rmdir dir2)
173         (sb-posix:rmdir dir)
174         (sb-posix:syscall-errno c))))
175   #.sb-posix::eacces)
176 \f
177 (deftest stat.1
178   (let* ((stat (sb-posix:stat *test-directory*))
179          (mode (sb-posix::stat-mode stat)))
180     ;; FIXME: Ugly ::s everywhere
181     (logand mode (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec)))
182   #.(logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
183
184 (deftest stat.2
185   (let* ((stat (sb-posix:stat "/"))
186          (mode (sb-posix::stat-mode stat)))
187     ;; it's logically possible for / to be writeable by others... but
188     ;; if it is, either someone is playing with strange security
189     ;; modules or they want to know about it anyway.
190     (logand mode sb-posix::s-iwoth))
191   0)
192     
193 (deftest stat.3
194   (let* ((now (get-universal-time))
195          ;; FIXME: (encode-universal-time 00 00 00 01 01 1970)
196          (unix-now (- now 2208988800))
197          (stat (sb-posix:stat *test-directory*))
198          (atime (sb-posix::stat-atime stat)))
199     ;; FIXME: breaks if mounted noatime :-(
200     (< (- atime unix-now) 10))
201   t)
202
203 (deftest stat.2
204   (let* ((stat (sb-posix:stat (make-pathname :directory '(:absolute :up))))
205          (mode (sb-posix::stat-mode stat)))
206     ;; it's logically possible for / to be writeable by others... but
207     ;; if it is, either someone is playing with strange security
208     ;; modules or they want to know about it anyway.
209     (logand mode sb-posix::s-iwoth))
210   0)
211
212 ;;; FIXME: add tests for carrying a stat structure around in the
213 ;;; optional argument to SB-POSIX:STAT
214
215 (deftest stat.error.1
216   (handler-case (sb-posix:stat "")
217     (sb-posix:syscall-error (c)
218       (sb-posix:syscall-errno c)))
219   #.sb-posix::enoent)
220
221 (deftest stat.error.2
222   (let* ((dir (merge-pathnames
223                (make-pathname :directory '(:relative "stat.error.2"))
224                *test-directory*))
225          (file (merge-pathnames
226                 (make-pathname :name "unstatable")
227                 dir)))
228     (sb-posix:mkdir dir +mode-rwx-all+)
229     (with-open-file (s file :direction :output)
230       (write "" :stream s))
231     (sb-posix:chmod dir 0)
232     (handler-case
233         (sb-posix:stat file)
234       (sb-posix:syscall-error (c)
235         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
236         (sb-posix:unlink file)
237         (sb-posix:rmdir dir)
238         (sb-posix:syscall-errno c))))
239   #.sb-posix::eacces)
240 \f
241 ;;; stat-mode tests
242 (defmacro with-stat-mode ((mode pathname) &body body)
243   (let ((stat (gensym)))
244     `(let* ((,stat (sb-posix:stat ,pathname))
245             (,mode (sb-posix::stat-mode ,stat)))
246        ,@body)))
247
248 (defmacro with-lstat-mode ((mode pathname) &body body)
249   (let ((stat (gensym)))
250     `(let* ((,stat (sb-posix:lstat ,pathname))
251             (,mode (sb-posix::stat-mode ,stat)))
252        ,@body)))
253
254 (deftest stat-mode.1
255   (with-stat-mode (mode *test-directory*)
256     (sb-posix:s-isreg mode))
257   nil)
258
259 (deftest stat-mode.2
260   (with-stat-mode (mode *test-directory*)
261     (sb-posix:s-isdir mode))
262   t)
263
264 (deftest stat-mode.3
265   (with-stat-mode (mode *test-directory*)
266     (sb-posix:s-ischr mode))
267   nil)
268
269 (deftest stat-mode.4
270   (with-stat-mode (mode *test-directory*)
271     (sb-posix:s-isblk mode))
272   nil)
273
274 (deftest stat-mode.5
275   (with-stat-mode (mode *test-directory*)
276     (sb-posix:s-isfifo mode))
277   nil)
278
279 (deftest stat-mode.6
280   (with-stat-mode (mode *test-directory*)
281     (sb-posix:s-issock mode))
282   nil)
283
284 (deftest stat-mode.7
285   (let ((link-pathname (make-pathname :name "stat-mode.7"
286                                       :defaults *test-directory*)))
287     (unwind-protect
288          (progn
289            (sb-posix:symlink *test-directory* link-pathname)
290            (with-lstat-mode (mode link-pathname)
291              (sb-posix:s-islnk mode)))
292       (ignore-errors (sb-posix:unlink link-pathname))))
293   t)
294
295 (deftest stat-mode.8
296   (let ((pathname (make-pathname :name "stat-mode.8"
297                                  :defaults *test-directory*)))
298     (unwind-protect
299          (progn
300            (with-open-file (out pathname :direction :output)
301              (write-line "test" out))
302            (with-stat-mode (mode pathname)
303              (sb-posix:s-isreg mode)))
304       (ignore-errors (delete-file pathname))))
305   t)
306 \f
307 ;;; see comment in filename's designator definition, in macros.lisp
308 (deftest filename-designator.1
309   (let ((file (format nil "~A/[foo].txt" (namestring *test-directory*))))
310     ;; creat() with a string as argument
311     (sb-posix:creat file 0)
312     ;; if this test fails, it will probably be with
313     ;; "System call error 2 (No such file or directory)"
314     (let ((*default-pathname-defaults* *test-directory*))
315       (sb-posix:unlink (car (directory "*.txt")))))
316   0)
317 \f
318 (deftest open.1
319   (let ((fd (sb-posix:open *test-directory* sb-posix::o-rdonly)))
320     (ignore-errors (sb-posix:close fd))
321     (< fd 0))
322   nil)
323
324 (deftest open.error.1
325   (handler-case (sb-posix:open *test-directory* sb-posix::o-wronly)
326     (sb-posix:syscall-error (c)
327       (sb-posix:syscall-errno c)))
328   #.sb-posix::eisdir)