1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-29 19:30:36 +02:00
guile/test-suite/tests/rnrs-libraries.test
Andy Wingo 5e470ea48f Fix R6RS imports of interfaces that use interfaces
* module/ice-9/r6rs-libraries.scm (resolve-r6rs-interface): In Guile, a
  module's public interface is just another module, and that means that
  it can import other modules as well.  Allow for R6RS modules that
  import module whose interfaces import other modules to access all
  visible bindings.
* test-suite/tests/rnrs-libraries.test ("import features"): Update
  test.
2016-04-14 12:35:55 +02:00

217 lines
7.3 KiB
Scheme

;;;; rnrs-libraries.test --- test library and import forms -*- scheme -*-
;;;; Copyright (C) 2010, 2012 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; This library is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;;; Lesser General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU Lesser General Public
;;;; License along with this library; if not, write to the Free Software
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
(define-module (tests rnrs-libraries)
#:use-module (test-suite lib))
;; First, check that Guile modules are r6rs modules.
;;
(with-test-prefix "ice-9 receive"
(define iface #f)
(pass-if "import"
(eval '(begin
(import (ice-9 receive))
#t)
(current-module)))
(pass-if "resolve-interface"
(module? (resolve-interface '(ice-9 receive))))
(set! iface (resolve-interface '(ice-9 receive)))
(pass-if "resolve-r6rs-interface"
(eq? iface (resolve-r6rs-interface '(ice-9 receive))))
(pass-if "resolve-r6rs-interface (2)"
(eq? iface (resolve-r6rs-interface '(library (ice-9 receive)))))
(pass-if "module uses"
(and (memq iface (module-uses (current-module))) #t))
(pass-if "interface contents"
(equal? '(receive)
(hash-map->list (lambda (sym var) sym) (module-obarray iface))))
(pass-if "interface uses"
(null? (module-uses iface)))
(pass-if "version"
(or (not (module-version iface))
(null? (module-version iface))))
(pass-if "calling receive from current env"
(equal? (eval '(receive (a b) (values 10 32)
(+ a b))
(current-module))
42)))
;; And check that r6rs modules are guile modules.
;;
(with-test-prefix "rnrs-test-a"
(define iface #f)
(pass-if "no double"
(not (module-local-variable (current-module) 'double)))
(pass-if "import"
(eval '(begin
(import (tests rnrs-test-a))
#t)
(current-module)))
(pass-if "still no double"
(not (module-local-variable (current-module) 'double)))
(pass-if "resolve-interface"
(module? (resolve-interface '(tests rnrs-test-a))))
(set! iface (resolve-interface '(tests rnrs-test-a)))
(pass-if "resolve-interface (2)"
(eq? iface (resolve-interface '(tests rnrs-test-a))))
(pass-if "resolve-r6rs-interface"
(eq? iface (resolve-r6rs-interface '(tests rnrs-test-a))))
(pass-if "resolve-r6rs-interface (2)"
(eq? iface (resolve-r6rs-interface '(library (tests rnrs-test-a)))))
(pass-if "module uses"
(and (memq iface (module-uses (current-module))) #t))
(pass-if "interface contents"
(equal? '(double)
(hash-map->list (lambda (sym var) sym) (module-obarray iface))))
(pass-if "interface uses"
(null? (module-uses iface)))
(pass-if "version"
(or (not (module-version iface))
(null? (module-version iface))))
(pass-if "calling double"
(equal? ((module-ref iface 'double) 10)
20))
(pass-if "calling double from current env"
(equal? (eval '(double 20) (current-module))
40)))
;; Guile should ignore explicit phase specifications
;;
(with-test-prefix "implicit phasing"
(with-test-prefix "in library form"
(pass-if "explicit phasing ignored"
(import (for (guile) (meta -1))) #t))
(with-test-prefix "in library form"
(pass-if "explicit phasing ignored"
(save-module-excursion
(lambda ()
(library (test)
(export)
(import (for (guile) (meta -1))))
#t)))))
;; Now import features.
;;
(with-test-prefix "import features"
(define iface #f)
(with-test-prefix "only"
(pass-if "contents"
(equal? '(+)
(hash-map->list
(lambda (sym var) sym)
(module-obarray (resolve-r6rs-interface '(only (guile) +)))))))
(with-test-prefix "except"
;; In Guile, interfaces can use other interfaces. For R6RS modules
;; that are imported as-is (without `except', etc), Guile will just
;; import them as-is. `(guile)' is one of those modules. For other
;; import kinds like `except', the resolve-r6rs-interface code will
;; go binding-by-binding and create a new flat interface. Anyway,
;; that means to compare an except interface with (guile), we're
;; comparing a flat interface with a deep interface, so we need to
;; do more work to get the set of bindings in (guile), knowing also
;; that some of those bindings could be duplicates.
(define (bound-name-count mod)
(define (module-for-each/nonlocal f mod)
(define (module-and-uses mod)
(let lp ((in (list mod)) (out '()))
(cond
((null? in) (reverse out))
((memq (car in) out) (lp (cdr in) out))
(else (lp (append (module-uses (car in)) (cdr in))
(cons (car in) out))))))
(for-each (lambda (mod)
(module-for-each f mod))
(module-and-uses mod)))
(hash-fold (lambda (sym var n) (1+ n))
0
(let ((t (make-hash-table)))
(module-for-each/nonlocal (lambda (sym var)
(hashq-set! t sym var))
mod)
t)))
(let ((except-+ (resolve-r6rs-interface '(except (guile) +))))
(pass-if "contains"
(equal? (bound-name-count except-+)
(1- (bound-name-count (resolve-interface '(guile))))))
(pass-if "does not contain"
(not (module-variable except-+ '+)))))
(with-test-prefix "prefix"
(let ((iface (resolve-r6rs-interface '(prefix (ice-9 q) q:))))
(pass-if "contains"
((module-ref iface 'q:q?) ((module-ref iface 'q:make-q))))
(pass-if "does not contain"
(not (module-local-variable iface 'make-q)))))
(with-test-prefix "rename"
(let ((iface (resolve-r6rs-interface
'(rename (only (guile) cons car cdr)
(cons snoc)
(car rac)
(cdr rdc)))))
(pass-if "contents"
(equal? '("rac" "rdc" "snoc")
(sort
(hash-map->list
(lambda (sym var) (symbol->string sym))
(module-obarray iface))
string<)))
(pass-if "contains"
(equal? 3 ((module-ref iface 'rac)
((module-ref iface 'snoc) 3 4))))))
(with-test-prefix "srfi"
(pass-if "renaming works"
(eq? (resolve-interface '(srfi srfi-1))
(resolve-r6rs-interface '(srfi :1)))
(eq? (resolve-interface '(srfi srfi-1))
(resolve-r6rs-interface '(srfi :1 lists)))))
(with-test-prefix "macro"
(pass-if "multiple clauses"
(eval '(begin
(import (rnrs) (for (rnrs) expand) (rnrs))
#t)
(current-module)))))