;;;; 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)))))