Fixes <https://issues.guix.gnu.org/65427>. * guix/read-print.scm (%special-forms): Add ‘parameterize’. * tests/read-print.scm: Add test. Reported-by: Maxime Devos <maximedevos@telenet.be> Change-Id: I922bffc527ade539cf2eb304acb25bc9c705a459
		
			
				
	
	
		
			441 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Scheme
		
	
	
	
	
	
			
		
		
	
	
			441 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Scheme
		
	
	
	
	
	
;;; GNU Guix --- Functional package management for GNU
 | 
						||
;;; Copyright © 2021-2023 Ludovic Courtès <ludo@gnu.org>
 | 
						||
;;;
 | 
						||
;;; This file is part of GNU Guix.
 | 
						||
;;;
 | 
						||
;;; GNU Guix is free software; you can redistribute it and/or modify it
 | 
						||
;;; under the terms of the GNU General Public License as published by
 | 
						||
;;; the Free Software Foundation; either version 3 of the License, or (at
 | 
						||
;;; your option) any later version.
 | 
						||
;;;
 | 
						||
;;; GNU Guix 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 General Public License for more details.
 | 
						||
;;;
 | 
						||
;;; You should have received a copy of the GNU General Public License
 | 
						||
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 | 
						||
 | 
						||
(define-module (tests-style)
 | 
						||
  #:use-module (guix read-print)
 | 
						||
  #:use-module (guix gexp)                        ;for the reader extensions
 | 
						||
  #:use-module (srfi srfi-34)
 | 
						||
  #:use-module (srfi srfi-35)
 | 
						||
  #:use-module (srfi srfi-64)
 | 
						||
  #:use-module (ice-9 match))
 | 
						||
 | 
						||
(define-syntax-rule (test-pretty-print str args ...)
 | 
						||
  "Test equality after a round-trip where STR is passed to
 | 
						||
'read-with-comments' and the resulting sexp is then passed to
 | 
						||
'pretty-print-with-comments'."
 | 
						||
  (test-equal str
 | 
						||
    (call-with-output-string
 | 
						||
      (lambda (port)
 | 
						||
        (let ((exp (call-with-input-string str
 | 
						||
                     read-with-comments)))
 | 
						||
         (pretty-print-with-comments port exp args ...))))))
 | 
						||
 | 
						||
(define-syntax-rule (test-pretty-print/sequence str args ...)
 | 
						||
  "Likewise, but read and print entire sequences rather than individual
 | 
						||
expressions."
 | 
						||
  (test-equal str
 | 
						||
    (call-with-output-string
 | 
						||
      (lambda (port)
 | 
						||
        (let ((lst (call-with-input-string str
 | 
						||
                     read-with-comments/sequence)))
 | 
						||
         (pretty-print-with-comments/splice port lst args ...))))))
 | 
						||
 | 
						||
 | 
						||
(test-begin "read-print")
 | 
						||
 | 
						||
(test-assert "read-with-comments: missing closing paren"
 | 
						||
  (guard (c ((error? c) #t))
 | 
						||
    (call-with-input-string "(what is going on?"
 | 
						||
      read-with-comments)))
 | 
						||
 | 
						||
(test-equal "read-with-comments: dot notation"
 | 
						||
  (cons 'a 'b)
 | 
						||
  (call-with-input-string "(a . b)"
 | 
						||
    read-with-comments))
 | 
						||
 | 
						||
(test-equal "read-with-comments: half dot notation"
 | 
						||
  '(lambda x x)
 | 
						||
  (call-with-input-string "(lambda (. x) x)"
 | 
						||
    read-with-comments))
 | 
						||
 | 
						||
(test-equal "read-with-comments: list with blank line"
 | 
						||
  `(list with ,(vertical-space 1) blank line)
 | 
						||
  (call-with-input-string "\
 | 
						||
(list with
 | 
						||
 | 
						||
      blank line)\n"
 | 
						||
    read-with-comments))
 | 
						||
 | 
						||
(test-equal "read-with-comments: list with multiple blank lines"
 | 
						||
  `(list with ,(comment ";multiple\n" #t)
 | 
						||
         ,(vertical-space 3) blank lines)
 | 
						||
  (call-with-input-string "\
 | 
						||
(list with ;multiple
 | 
						||
 | 
						||
 | 
						||
 | 
						||
      blank lines)\n"
 | 
						||
    read-with-comments))
 | 
						||
 | 
						||
(test-equal "read-with-comments: top-level blank lines"
 | 
						||
  (list (vertical-space 2) '(a b c) (vertical-space 2))
 | 
						||
  (call-with-input-string "
 | 
						||
 | 
						||
(a b c)\n\n"
 | 
						||
    (lambda (port)
 | 
						||
      (list (read-with-comments port)
 | 
						||
            (read-with-comments port)
 | 
						||
            (read-with-comments port)))))
 | 
						||
 | 
						||
(test-equal "read-with-comments: top-level page break"
 | 
						||
  (list (comment ";; Begin.\n") (vertical-space 1)
 | 
						||
        (page-break)
 | 
						||
        (comment ";; End.\n"))
 | 
						||
  (call-with-input-string "\
 | 
						||
;; Begin.
 | 
						||
 | 
						||
 | 
						||
;; End.\n"
 | 
						||
    (lambda (port)
 | 
						||
      (list (read-with-comments port)
 | 
						||
            (read-with-comments port)
 | 
						||
            (read-with-comments port)
 | 
						||
            (read-with-comments port)))))
 | 
						||
 | 
						||
(test-pretty-print "(list 1 2 3 4)")
 | 
						||
(test-pretty-print "((a . 1) (b . 2))")
 | 
						||
(test-pretty-print "(a b c . boom)")
 | 
						||
(test-pretty-print "(list 1
 | 
						||
                          2
 | 
						||
                          3
 | 
						||
                          4)"
 | 
						||
                   #:long-list 3
 | 
						||
                   #:indent 20)
 | 
						||
(test-pretty-print "\
 | 
						||
(list abc
 | 
						||
      def)"
 | 
						||
                   #:max-width 11)
 | 
						||
(test-pretty-print "\
 | 
						||
(#:foo
 | 
						||
 #:bar)"
 | 
						||
                   #:max-width 10)
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(#:first 1
 | 
						||
 #:second 2
 | 
						||
 #:third 3)")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
((x
 | 
						||
  1)
 | 
						||
 (y
 | 
						||
  2)
 | 
						||
 (z
 | 
						||
  3))"
 | 
						||
                   #:max-width 3)
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(let ((x 1)
 | 
						||
      (y 2)
 | 
						||
      (z 3)
 | 
						||
      (p 4))
 | 
						||
  (+ x y))"
 | 
						||
                   #:max-width 11)
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(begin
 | 
						||
  1+ 1- 123/ 456*
 | 
						||
  (1+ 41))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(lambda (x y)
 | 
						||
  ;; This is a procedure.
 | 
						||
  (let ((z (+ x y)))
 | 
						||
    (* z z)))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(case x
 | 
						||
  ((1)
 | 
						||
   'one)
 | 
						||
  ((2)
 | 
						||
   'two))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(cond
 | 
						||
  ((zero? x)
 | 
						||
   'zero)
 | 
						||
  ((odd? x)
 | 
						||
   'odd)
 | 
						||
  (else #f))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(parameterize ((a 1)
 | 
						||
               (b 2))
 | 
						||
  (call f g h))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
#~(string-append #$coreutils \"/bin/uname\")")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(package
 | 
						||
  (inherit coreutils)
 | 
						||
  (version \"42\"))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(modify-phases %standard-phases
 | 
						||
  (add-after 'unpack 'post-unpack
 | 
						||
    (lambda _
 | 
						||
      #t))
 | 
						||
  (add-before 'check 'pre-check
 | 
						||
    (lambda* (#:key inputs #:allow-other-keys)
 | 
						||
      do things ...)))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(#:phases (modify-phases sdfsdf
 | 
						||
            (add-before 'x 'y
 | 
						||
              (lambda _
 | 
						||
                xyz))))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(string-append \"a\\tb\" \"\\n\")")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(display \"This is a very long string.
 | 
						||
It contains line breaks, which are preserved,
 | 
						||
because it's a long string.\")")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(description \"abcdefghijkl
 | 
						||
mnopqrstuvwxyz.\")"
 | 
						||
                   #:max-width 30)
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(description
 | 
						||
 \"abcdefghijkl
 | 
						||
mnopqrstuvwxyz.\")"
 | 
						||
                   #:max-width 12)
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(description
 | 
						||
 \"abcdefghijklmnopqrstuvwxyz\")"
 | 
						||
                   #:max-width 33)
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(list ;margin comment
 | 
						||
      a b c)")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(list
 | 
						||
 ;; This is a line comment immediately following the list head.
 | 
						||
 #:test-flags #~(list \"-m\" \"not external and not samples\"))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(modify-phases %standard-phases
 | 
						||
  (replace 'build
 | 
						||
    ;; Nicely indented in 'modify-phases' context.
 | 
						||
    (lambda _
 | 
						||
      #t)))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(modify-inputs inputs
 | 
						||
  ;; Regular indentation for 'replace' here.
 | 
						||
  (replace \"gmp\" gmp))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
#~(modify-phases phases
 | 
						||
    (add-after 'whatever 'something-else
 | 
						||
      (lambda _
 | 
						||
        ;; This comment appears inside a gexp.
 | 
						||
        42)))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
#~(list #$@(list coreutils ;yup
 | 
						||
                 grep) ;margin comment
 | 
						||
        #+sed
 | 
						||
 | 
						||
        ;; Line comment.
 | 
						||
        #$grep)")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(package
 | 
						||
  ;; Here 'source', 'sha256', and 'arguments' must be
 | 
						||
  ;; immediately followed by a newline.
 | 
						||
  (source
 | 
						||
   (origin
 | 
						||
     (method url-fetch)
 | 
						||
     (sha256
 | 
						||
      (base32 \"not a real base32 string\"))))
 | 
						||
  (arguments
 | 
						||
   '(#:phases %standard-phases
 | 
						||
     #:tests? #f)))")
 | 
						||
 | 
						||
;; '#:key value' is kept on the same line.
 | 
						||
(test-pretty-print "\
 | 
						||
(package
 | 
						||
  (name \"keyword-value-same-line\")
 | 
						||
  (arguments
 | 
						||
   (list
 | 
						||
    #:phases #~(modify-phases %standard-phases
 | 
						||
                 (add-before 'x 'y
 | 
						||
                   (lambda* (#:key inputs #:allow-other-keys)
 | 
						||
                     (foo bar baz))))
 | 
						||
    #:make-flags #~'(\"ANSWER=42\")
 | 
						||
    #:tests? #f)))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(let ((x 1)
 | 
						||
      (y 2)
 | 
						||
      (z (let* ((a 3)
 | 
						||
                (b 4))
 | 
						||
           (+ a b))))
 | 
						||
  (list x y z))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(begin
 | 
						||
  (chmod \"foo\" #o750)
 | 
						||
  (chmod port
 | 
						||
         (logand #o644
 | 
						||
                 (lognot (umask))))
 | 
						||
  (logand #x7f xyz))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(substitute-keyword-arguments (package-arguments x)
 | 
						||
  ((#:phases phases)
 | 
						||
   `(modify-phases ,phases
 | 
						||
      (add-before 'build 'do-things
 | 
						||
        (lambda _
 | 
						||
          #t))))
 | 
						||
  ((#:configure-flags flags)
 | 
						||
   `(cons \"--without-any-problem\"
 | 
						||
          ,flags)))")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(vertical-space one:
 | 
						||
 | 
						||
                two:
 | 
						||
 | 
						||
 | 
						||
                three:
 | 
						||
 | 
						||
 | 
						||
 | 
						||
                end)")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(vertical-space one
 | 
						||
 | 
						||
                ;; Comment after blank line.
 | 
						||
                two)")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(begin
 | 
						||
  break
 | 
						||
 | 
						||
  ;; page break above
 | 
						||
  end)")
 | 
						||
 | 
						||
(test-pretty-print "\
 | 
						||
(home-environment
 | 
						||
  (services
 | 
						||
   (list (service-type home-bash-service-type))))")
 | 
						||
 | 
						||
(test-pretty-print/sequence "\
 | 
						||
;;; This is a top-level comment.
 | 
						||
 | 
						||
 | 
						||
;; Above is a page break.
 | 
						||
(this is an sexp
 | 
						||
      ;; with a comment
 | 
						||
      !!)
 | 
						||
 | 
						||
;; The end.\n")
 | 
						||
 | 
						||
(test-pretty-print/sequence "
 | 
						||
;;; Hello!
 | 
						||
;;; Notice that there are three semicolons here.
 | 
						||
 | 
						||
(define-module (foo bar)
 | 
						||
  #:use-module (guix)
 | 
						||
  #:use-module (gnu))
 | 
						||
 | 
						||
 | 
						||
;; And now, the OS.
 | 
						||
(operating-system
 | 
						||
  (host-name \"komputilo\")
 | 
						||
  (locale \"eo_EO.UTF-8\")
 | 
						||
 | 
						||
  (services
 | 
						||
   (cons (service mcron-service-type) %base-services)))\n"
 | 
						||
                            #:format-comment canonicalize-comment)
 | 
						||
 | 
						||
(test-equal "pretty-print-with-comments, canonicalize-comment"
 | 
						||
  "\
 | 
						||
(list abc
 | 
						||
      ;; Not a margin comment.
 | 
						||
      ;; Ditto.
 | 
						||
      ;;
 | 
						||
      ;; There's a blank line above.
 | 
						||
      def ;margin comment
 | 
						||
      ghi)"
 | 
						||
  (let ((sexp (call-with-input-string
 | 
						||
                  "\
 | 
						||
(list abc
 | 
						||
  ;Not a margin comment.
 | 
						||
  ;;;  Ditto.
 | 
						||
  ;;;;;
 | 
						||
  ; There's a blank line above.
 | 
						||
  def  ;; margin comment
 | 
						||
  ghi)"
 | 
						||
                read-with-comments)))
 | 
						||
    (call-with-output-string
 | 
						||
      (lambda (port)
 | 
						||
        (pretty-print-with-comments port sexp
 | 
						||
                                    #:format-comment
 | 
						||
                                    canonicalize-comment)))))
 | 
						||
 | 
						||
(test-equal "pretty-print-with-comments, canonicalize-vertical-space"
 | 
						||
  "\
 | 
						||
(list abc
 | 
						||
 | 
						||
      def
 | 
						||
 | 
						||
      ;; last one
 | 
						||
      ghi)"
 | 
						||
  (let ((sexp (call-with-input-string
 | 
						||
                  "\
 | 
						||
(list abc
 | 
						||
 | 
						||
 | 
						||
 | 
						||
  def
 | 
						||
 | 
						||
 | 
						||
;; last one
 | 
						||
  ghi)"
 | 
						||
                read-with-comments)))
 | 
						||
    (call-with-output-string
 | 
						||
      (lambda (port)
 | 
						||
        (pretty-print-with-comments port sexp
 | 
						||
                                    #:format-vertical-space
 | 
						||
                                    canonicalize-vertical-space)))))
 | 
						||
 | 
						||
(test-equal "pretty-print-with-comments, multi-line comment"
 | 
						||
  "\
 | 
						||
(list abc
 | 
						||
      ;; This comment spans
 | 
						||
      ;; two lines.
 | 
						||
      def)"
 | 
						||
  (call-with-output-string
 | 
						||
    (lambda (port)
 | 
						||
      (pretty-print-with-comments port
 | 
						||
                                  `(list abc ,(comment "\
 | 
						||
;; This comment spans\n
 | 
						||
;; two lines.\n")
 | 
						||
                                         def)))))
 | 
						||
 | 
						||
(test-end)
 |