Skip to content
tests.lisp 8.88 KiB
Newer Older
(defpackage :scribble-test
  (:use :common-lisp :scribble :hu.dwim.stefil :fare-utils))

(in-package :scribble-test)

(deftest test-column-modifier ()
  (macrolet ((ccm (x y z)
               `(is (equal (multiple-value-list
                            (combine-column-modifiers ,@x ,@y))
                           ',z)))
             (scm (x a b c)
               `(is (equal (multiple-value-list
                            (string-column-modifier ,(format nil x #\tab)))
                           '(,a ,b ,c)))))
    (scm "abcde" 5 nil nil)
    (scm "foo
abcde" nil 5 nil)
    (scm "foo bar~%abcde" nil 5 7)
    (scm "abcd~cfgh" 4 3 nil)
    (scm "foo bar~%abcde~cfgh" nil 11 7)
    (scm "~%abcde~cfgh" nil 11 0)
    (ccm (15 nil) (nil 23) (nil 23))
    (ccm (nil 15) (nil 23) (nil 23))
    (ccm (5 15) (nil 23) (nil 23))
    (ccm (15 nil) (23 nil) (38 nil))
    (ccm (nil 15) (23 nil) (nil 38))
    (ccm (5 15) (23 nil) (5 38))
    (ccm (nil 15) (23 42) (nil 82))
    (ccm (15 nil) (23 42) (38 42))
    (ccm (5 15) (23 42) (5 82))))


(defparameter *u* "/tmp/u")

(defparameter *external-format*
  #-ccl :default
  #+ccl (ccl:make-external-format :character-encoding :utf-8))

(deftest test-file-position ()
  (with-open-file (s *u* :direction :output :if-exists :rename-and-delete)
    (princ "Hello, World
Faré λ 自由 foo
æéïôù
" s))

  (with-open-file (s *u* :direction :input :external-format *external-format*)
    (is (file-length s) 42)
    (let ((cpos
           (loop :for p = (file-position s)
             :for st = "" :then (concatenate 'string st (string c))
             :for c = (read-char s nil nil)
             :for col = (multiple-value-bind (u a) (string-column-modifier st)
                          (nth-value 1 (combine-column-modifiers nil 0 u a)))
             ;;:for i :from 0 :for nil = (format t "~&pos ~2D ~2D ~2D ~S~%" i p col c)
             :while c
             :count (babel:string-size-in-octets (string c)) :into expectedp :do
             (is p expectedp)
             :collect (list c p st col))))
      (loop :for (c p st col) :in cpos :do
        (file-position s p)
        (is (eql (file-position s) p))
        (is (eql (read-char s) c))
        (file-position s 0)
        (is (equal (read-stream-to-pos s p) st))
        (is (eql (file-position s) p))
        (is (eql (stream-line-column-harder s) col))
        )))

  (delete-file *u*)
  t)

(deftest test-scribble-at ()
  ;; Tests taken from http://docs.racket-lang.org/scribble/reader.html
  (macrolet ((a (x y)
               `(is (equal (p ,x)
                           ',(subst scribble::*lf* '*lf* y))))
             (a* (&rest r)
               `(flet ((p (x)
                         (let ((*readtable* scribble::*scribble-readtable*))
                           (read-from-string (strcat "      " x)))))
                  ,@(loop :for (x y) :on r :by #'cddr :collect `(a ,x ,y)))))
    (a*
     "@foo{blah blah blah}" (foo "blah blah blah")
     "@foo{blah \"blah\" (`blah'?)}" (foo "blah \"blah\" (`blah'?)")
     "@foo[1 2]{3 4}" (foo 1 2 "3 4")
     "@foo[1 2 3 4]" (foo 1 2 3 4)
     "@foo[:width 2]{blah blah}" (foo :width 2 "blah blah")
     "@foo{blah blah
           yada yada}" (foo "blah blah" *lf* "yada yada")
     "@foo{
        blah blah
        yada yada
     }" (foo "blah blah" *lf* "yada yada")
     "@foo{bar @baz{3}
           blah}" (foo "bar " (baz "3") *lf* "blah")
     "@foo{@b{@u[3] @u{4}}
           blah}" (foo (b (u 3) " " (u "4")) *lf* "blah")
     "@C{while (*(p++))
           *p = '\\n';}" (C "while (*(p++))" *lf* "  " "*p = '\\n';")
     "@{blah blah}" ("blah blah")
     "@{blah @[3]}" ("blah " (3))
     "'@{foo
         bar
         baz}" '("foo" *lf* "bar" *lf* "baz")
     "@foo" foo
     "@{blah @foo blah}" ("blah " foo " blah")
     "@{blah @:foo blah}" ("blah " :foo " blah")
     "@{blah @|foo|: blah}" ("blah " foo ": blah")
     "@foo{(+ 1 2) -> @(+ 1 2)!}" (foo "(+ 1 2) -> " (+ 1 2) "!")
     "@foo{A @\"string\" escape}" (foo "A string escape")
     "@foo{eli@\"@\"barzilay.org}" (foo "eli@barzilay.org")
     "@foo{A @\"{\" begins a block}" (foo "A { begins a block")
     "@C{while (*(p++)) {
           *p = '\\n';
         }}" (C "while (*(p++)) {" *lf* "  " "*p = '\\n';" *lf* "}")
     "@foo|{bar}@{baz}|" (foo "bar}@{baz")
     "@foo|{bar |@x{X} baz}|" (foo "bar " (x "X") " baz")
     "@foo|{bar |@x|{@}| baz}|" (foo "bar " (x "@") " baz")
     "@foo|--{bar}@|{baz}--|" (foo "bar}@|{baz")
     "@foo|<<{bar}@|{baz}>>|" (foo "bar}@|{baz")
     "(define \\@email \"foo@bar.com\")" (define \@email "foo@bar.com")
     ;;"(define |@atchar| #\\@)" (define \@atchar #\@)
     "@foo{bar @baz[2 3] {4 5}}" (foo "bar " (baz 2 3) " {4 5}")
     ;;"@`',@foo{blah}" `',@(foo "blah")
     ;;"@#`#'#,@foo{blah}"  #`#'#,@(foo "blah")
     "@(lambda (x) x){blah}" ((lambda (x) x) "blah")
     ;;"@`(unquote foo){blah}" `(,foo  "blah")
     "@{foo bar
        baz}" ("foo bar" *lf* "baz")
     "@'{foo bar
         baz}" '("foo bar" *lf* "baz")
     "@foo{bar @; comment
           baz@;
           blah}" (foo "bar bazblah")
     "@foo{x @y z}" (foo "x " y " z")
     "@foo{x @(* y 2) z}" (foo "x " (* y 2) " z")
     "@{@foo bar}" (foo " bar")
     "@@foo{bar}{baz}" ((foo "bar") "baz")
     "@foo[1 (* 2 3)]{bar}" (foo 1 (* 2 3) "bar")
     "@foo[@bar{...}]{blah}" (foo (bar "...") "blah")
     "@foo[bar]" (foo bar)
     "@foo{bar @f[x] baz}" (foo "bar " (f x) " baz")
     "@foo[]{bar}" (foo "bar")
     "@foo[]" (foo)
     "@foo" foo
     "@foo{}" (foo)
     "@foo[:style 'big]{bar}" (foo :style 'big "bar") ; #:style in racket
     "@foo{f{o}o}" (foo "f{o}o")
     "@foo{{{}}{}}" (foo "{{}}{}")
     "@foo{bar}" (foo "bar")
     "@foo{ bar }" (foo " bar ")
     "@foo[1]{ bar }" (foo 1 " bar ")
     "@foo{a @bar{b} c}" (foo "a " (bar "b") " c")
     "@foo{a @bar c}" (foo "a " bar " c")
     "@foo{a @(bar 2) c}" (foo "a " (bar 2) " c")
     "@foo{A @\"}\" marks the end}" (foo "A } marks the end")
     "@foo{The prefix: @\"@\".}" (foo "The prefix: @.")
     "@foo{@\"@x{y}\" --> (x \"y\")}" (foo "@x{y} --> (x \"y\")")
     "@foo|{...}|" (foo "...")
     "@foo|{\"}\" follows \"{\"}|" (foo "\"}\" follows \"{\"")
     "@foo|{Nesting |{is}| ok}|" (foo "Nesting |{is}| ok")
     "@foo|{Maze
            |@bar{is}
            Life!}|" (foo "Maze" *lf*
                          (bar "is") *lf*
                          "Life!")
     "@t|{In |@i|{sub|@\"@\"s}| too}|" (t "In " (i "sub@s") " too")
     "@foo|<<<{@x{foo} |@{bar}|.}>>>|" (foo "@x{foo} |@{bar}|.")
     "@foo|!!{X |!!@b{Y}...}!!|" (foo "X " (b "Y") "...")
     "@foo{foo@bar.}" (foo "foo" bar.)
     "@foo{foo@|bar|.}" (foo "foo" bar ".")
     "@foo{foo@3.0}" (foo "foo" 3.0) ;; orig had 3. 3.0
     "@foo{foo@|3|.0}" (foo "foo" 3 ".0") ;; orign had no 0
     "@foo{foo@|(f 1)|{bar}}" (foo "foo" (f 1) "{bar}")
     "@foo{foo@|bar|[1]{baz}}" (foo "foo" bar "[1]{baz}")
     "@foo{x@\"y\"z}" (foo "xyz")
     "@foo{x@|\"y\"|z}" (foo "x" "y" "z")
     "@foo{x@|1 (+ 2 3) 4|y}" (foo "x" 1 (+ 2 3) 4 "y")
     "@foo{x@|*
              *|y}" (foo "x" *
          * "y")
     "@foo{Alice@||Bob@|
           |Carol}" (foo "Alice" "Bob" "Carol")
     "@|{blah}|" ("blah")
     "@|{blah |@foo bleh}|" ("blah " foo " bleh")
     "@foo{First line@;{there is still a
                        newline here;}
           Second line}" (foo "First line" *lf* "Second line")
     "@foo{A long @;
           single-@;
           string arg.}" (foo "A long single-string arg.")
     "@foo{bar}" (foo "bar")
     "@foo{ bar }" (foo " bar ")
     "@foo{ bar
           baz }" (foo " bar" *lf* "baz ")
     "@foo{bar
      }" (foo "bar")
     "@foo{
      bar
      }" (foo "bar")
     "@foo{

      bar

      }" (foo *lf* "bar" *lf*)
      "@foo{
      bar

      baz
      }" (foo "bar" *lf* *lf* "baz")
     "@foo{
      }" (foo *lf*)
     "@foo{

      }" (foo *lf* *lf*)
     "@foo{ bar
      baz }" (foo " bar" *lf* "baz ")
     "@foo{
        bar
        baz
        blah
      }" (foo "bar" *lf* "baz" *lf* "blah")
     "@foo{
      begin
        x++;
      end}" (foo "begin" *lf* "  " "x++;" *lf* "end")
     "@foo{
         a
        b
       c}" (foo "  " "a" *lf* " " "b" *lf* "c")
     "@foo{bar
             baz
           bbb}" (foo "bar" *lf* "  ""baz" *lf* "bbb")
     "@foo{ bar
              baz
            bbb}" (foo " bar" *lf* "   " "baz" *lf* " " "bbb")
     "@foo{bar
         baz
         bbb}" (foo "bar" *lf* "baz" *lf* "bbb")
     "@foo{ bar
           baz
           bbb}" (foo " bar" *lf* "baz" *lf* "bbb")
     "@foo{ bar
         baz
           bbb}" (foo " bar" *lf* "baz" *lf* "  " "bbb")
     "@text{Some @b{bold
                    text}, and
            more text.}" (text "Some " (b "bold" *lf* "text")", and" *lf* "more text.")
#| ;;; properly render this?
;;; a formatter will need to apply the 2-space indentation to the rendering of the bold body.
@code{
  begin
    i = 1, r = 1
    @bold{while i < n do
            r *= i++
          done}
  end
}
|#
     "@foo{
        @|| bar @||
        @|| baz}" (foo " bar " *lf* " baz")
)))