add fluid tests
[bpt/guile.git] / test-suite / tests / modules.test
CommitLineData
6e7d5622
KR
1;;;; modules.test --- exercise some of guile's module stuff -*- scheme -*-
2
16f451f3 3;;;; Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
6e7d5622
KR
4;;;;
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
53befeb7
NJ
8;;;; version 3 of the License, or (at your option) any later version.
9;;;;
6e7d5622
KR
10;;;; This library is distributed in the hope that it will be useful,
11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
53befeb7 14;;;;
6e7d5622
KR
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
608860a5
LC
19(define-module (test-suite test-modules)
20 :use-module (srfi srfi-1)
21 :use-module ((ice-9 streams) ;; for test purposes
22 #:renamer (symbol-prefix-proc 's:))
23 :use-module (test-suite lib))
24
25
26(define (every? . args)
27 (not (not (apply every args))))
28
29
30\f
31;;;
32;;; Foundations.
33;;;
34
35(with-test-prefix "foundations"
36
16f451f3
LC
37 (pass-if "modules don't remain anonymous"
38 ;; This is a requirement for `psyntax': it stores module names and relies
39 ;; on being able to `resolve-module' them.
40 (let ((m (make-module)))
41 (and (module-name m)
42 (eq? m (resolve-module (module-name m))))))
43
608860a5
LC
44 (pass-if "module-add!"
45 (let ((m (make-module))
46 (value (cons 'x 'y)))
47 (module-add! m 'something (make-variable value))
48 (eq? (module-ref m 'something) value)))
49
50 (pass-if "module-define!"
51 (let ((m (make-module))
52 (value (cons 'x 'y)))
53 (module-define! m 'something value)
54 (eq? (module-ref m 'something) value)))
55
56 (pass-if "module-use!"
57 (let ((m (make-module))
58 (import (make-module)))
59 (module-define! m 'something 'something)
60 (module-define! import 'imported 'imported)
61 (module-use! m import)
62 (and (eq? (module-ref m 'something) 'something)
63 (eq? (module-ref m 'imported) 'imported)
64 (module-local-variable m 'something)
65 (not (module-local-variable m 'imported))
66 #t)))
67
68 (pass-if "module-use! (duplicates local binding)"
69 ;; Imported bindings can't override locale bindings.
70 (let ((m (make-module))
71 (import (make-module)))
72 (module-define! m 'something 'something)
73 (module-define! import 'something 'imported)
74 (module-use! m import)
75 (eq? (module-ref m 'something) 'something)))
76
77 (pass-if "module-locally-bound?"
78 (let ((m (make-module))
79 (import (make-module)))
80 (module-define! m 'something #t)
81 (module-define! import 'imported #t)
82 (module-use! m import)
83 (and (module-locally-bound? m 'something)
84 (not (module-locally-bound? m 'imported)))))
85
86 (pass-if "module-{local-,}variable"
87 (let ((m (make-module))
88 (import (make-module)))
89 (module-define! m 'local #t)
90 (module-define! import 'imported #t)
91 (module-use! m import)
92 (and (module-local-variable m 'local)
93 (not (module-local-variable m 'imported))
94 (eq? (module-variable m 'local)
95 (module-local-variable m 'local))
96 (eq? (module-local-variable import 'imported)
97 (module-variable m 'imported)))))
98
99 (pass-if "module-import-interface"
100 (and (every? (lambda (sym iface)
101 (eq? (module-import-interface (current-module) sym)
102 iface))
103 '(current-module exception:bad-variable every)
104 (cons the-scm-module
105 (map resolve-interface
106 '((test-suite lib) (srfi srfi-1)))))
107
108 ;; For renamed bindings, a custom interface is used so we can't
109 ;; check for equality with `eq?'.
110 (every? (lambda (sym iface)
111 (let ((import
112 (module-import-interface (current-module) sym)))
113 (equal? (module-name import)
114 (module-name iface))))
115 '(s:make-stream s:stream-car s:stream-cdr)
116 (make-list 3 (resolve-interface '(ice-9 streams))))))
117
118 (pass-if "module-reverse-lookup"
119 (let ((mods '((srfi srfi-1) (test-suite lib) (ice-9 streams)))
120 (syms '(every exception:bad-variable make-stream))
121 (locals '(every exception:bad-variable s:make-stream)))
122 (every? (lambda (var sym)
123 (eq? (module-reverse-lookup (current-module) var)
124 sym))
125 (map module-variable
126 (map resolve-interface mods)
127 syms)
128 locals))))
129
130
131\f
132;;;
133;;; Observers.
134;;;
135
136(with-test-prefix "observers"
137
138 (pass-if "weak observer invoked"
139 (let* ((m (make-module))
140 (invoked 0))
141 (module-observe-weak m (lambda (mod)
142 (if (eq? mod m)
143 (set! invoked (+ invoked 1)))))
144 (module-define! m 'something 2)
145 (module-define! m 'something-else 1)
146 (= invoked 2)))
147
148 (pass-if "all weak observers invoked"
149 ;; With the two-argument `module-observe-weak' available in previous
150 ;; versions, the observer would get unregistered as soon as the observing
151 ;; closure gets GC'd, making it impossible to use an anonymous lambda as
152 ;; the observing procedure.
153
154 (let* ((m (make-module))
155 (observer-count 500)
156 (observer-ids (let loop ((i observer-count)
157 (ids '()))
158 (if (= i 0)
159 ids
160 (loop (- i 1) (cons (make-module) ids)))))
161 (observers-invoked (make-hash-table observer-count)))
162
163 ;; register weak observers
164 (for-each (lambda (id)
165 (module-observe-weak m id
166 (lambda (m)
167 (hashq-set! observers-invoked
168 id #t))))
169 observer-ids)
170
171 (gc)
172
173 ;; invoke them
174 (module-call-observers m)
175
176 ;; make sure all of them were invoked
177 (->bool (every (lambda (id)
178 (hashq-ref observers-invoked id))
179 observer-ids))))
180
181 (pass-if "imported bindings updated"
182 (let ((m (make-module))
183 (imported (make-module)))
184 ;; Beautify them, notably adding them a public interface.
185 (beautify-user-module! m)
186 (beautify-user-module! imported)
187
188 (module-use! m (module-public-interface imported))
189 (module-define! imported 'imported-binding #t)
190
191 ;; At this point, `imported-binding' is local to IMPORTED.
192 (and (not (module-variable m 'imported-binding))
193 (begin
194 ;; Export `imported-binding' from IMPORTED.
195 (module-export! imported '(imported-binding))
196
197 ;; Make sure it is now visible from M.
198 (module-ref m 'imported-binding))))))
199
200
201\f
202;;;
203;;; Duplicate bindings handling.
204;;;
205
206(with-test-prefix "duplicate bindings"
207
208 (pass-if "simple duplicate handler"
209 ;; Import the same binding twice.
210 (let* ((m (make-module))
211 (import1 (make-module))
212 (import2 (make-module))
213 (handler-invoked? #f)
214 (handler (lambda (module name int1 val1 int2 val2 var val)
215 (set! handler-invoked? #t)
216 ;; Keep the first binding.
217 (or var (module-local-variable int1 name)))))
218
219 (set-module-duplicates-handlers! m (list handler))
220 (module-define! m 'something 'something)
221 (set-module-name! import1 'imported-module-1)
222 (set-module-name! import2 'imported-module-2)
223 (module-define! import1 'imported 'imported-1)
224 (module-define! import2 'imported 'imported-2)
225 (module-use! m import1)
226 (module-use! m import2)
227 (and (eq? (module-ref m 'imported) 'imported-1)
228 handler-invoked?))))
229
230\f
231;;;
232;;; Lazy binder.
233;;;
234
235(with-test-prefix "lazy binder"
236
237 (pass-if "not invoked"
238 (let ((m (make-module))
239 (invoked? #f))
240 (module-define! m 'something 2)
241 (set-module-binder! m (lambda args (set! invoked? #t) #f))
242 (and (module-ref m 'something)
243 (not invoked?))))
244
245 (pass-if "not invoked (module-add!)"
246 (let ((m (make-module))
247 (invoked? #f))
248 (set-module-binder! m (lambda args (set! invoked? #t) #f))
249 (module-add! m 'something (make-variable 2))
250 (and (module-ref m 'something)
251 (not invoked?))))
252
253 (pass-if "invoked (module-ref)"
254 (let ((m (make-module))
255 (invoked? #f))
256 (set-module-binder! m (lambda args (set! invoked? #t) #f))
257 (false-if-exception (module-ref m 'something))
258 invoked?))
259
260 (pass-if "invoked (module-define!)"
261 (let ((m (make-module))
262 (invoked? #f))
263 (set-module-binder! m (lambda args (set! invoked? #t) #f))
264 (module-define! m 'something 2)
265 (and invoked?
266 (eq? (module-ref m 'something) 2))))
267
268 (pass-if "honored (ref)"
269 (let ((m (make-module))
270 (invoked? #f)
271 (value (cons 'x 'y)))
272 (set-module-binder! m
273 (lambda (mod sym define?)
274 (set! invoked? #t)
275 (cond ((not (eq? m mod))
276 (error "invalid module" mod))
277 (define?
278 (error "DEFINE? shouldn't be set"))
279 (else
280 (make-variable value)))))
281 (and (eq? (module-ref m 'something) value)
282 invoked?))))
283
284
285\f
286;;;
287;;; Higher-level features.
288;;;
6e7d5622
KR
289
290(with-test-prefix "autoload"
291
608860a5
LC
292 (pass-if "module-autoload!"
293 (let ((m (make-module)))
294 (module-autoload! m '(ice-9 q) '(make-q))
295 (not (not (module-ref m 'make-q)))))
296
6e7d5622
KR
297 (pass-if "autoloaded"
298 (catch #t
299 (lambda ()
300 ;; Simple autoloading.
301 (eval '(begin
302 (define-module (test-autoload-one)
303 :autoload (ice-9 q) (make-q))
304 (not (not make-q)))
305 (current-module)))
306 (lambda (key . args)
307 #f)))
308
309 ;; In Guile 1.8.0 this failed because the binder in
310 ;; `make-autoload-interface' would try to remove the autoload interface
311 ;; from the module's "uses" without making sure it is still part of these
312 ;; "uses".
313 ;;
314 (pass-if "autoloaded+used"
315 (catch #t
316 (lambda ()
317 (eval '(begin
318 (define-module (test-autoload-two)
319 :autoload (ice-9 q) (make-q)
320 :use-module (ice-9 q))
321 (not (not make-q)))
322 (current-module)))
323 (lambda (key . args)
324 #f))))