From 556df92d9ce3a3825088095c3ddeb2e7964d7100 Mon Sep 17 00:00:00 2001 From: Marce Coll Date: Tue, 5 Mar 2024 20:49:01 +0100 Subject: [PATCH] feat: Added tests --- .github/workflows/test.yml | 34 ++++++++++++++++++++++++++++++ chobun.asd | 13 +++++++++--- chobun.lisp | 19 +++++++++++------ t/chobun.lisp | 42 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 t/chobun.lisp diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..0582f63 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: test +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + lisp: + - sbcl-bin + - ccl-bin + + defaults: + run: + shell: bash + env: + LISP: ${{ matrix.lisp }} + + steps: + - uses: actions/checkout@v4 + - name: Restore cache + id: cache-ql + uses: actions/cache@v3 + with: + path: | + ~/.roswell + ~/.cache/common-lisp + key: ${{ runner.os }}-ql + - name: Install Lisp + uses: 40ants/setup-lisp@v2 + with: + asdf-system: chobun + - name: Run tests + with: + asdf-system: chobun + diff --git a/chobun.asd b/chobun.asd index f465255..1eaadb9 100644 --- a/chobun.asd +++ b/chobun.asd @@ -1,3 +1,10 @@ -(asdf:defsystem "chobun" - :depends-on ("bedrock") - :components ((:file "chobun"))) +(asdf:defsystem :chobun + :depends-on (:bedrock) + :components ((:file "chobun")) + :in-order-to ((test-op (test-op :chobun/test)))) + +(asdf:defsystem :chobun/test + :depends-on (:chobun :parachute :split-sequence) + :components ((:module "t" + :components ((:file "chobun")))) + :perform (asdf:test-op (op c) (uiop:symbol-call :parachute :test-toplevel :chobun/test))) diff --git a/chobun.lisp b/chobun.lisp index fdacf5f..b2d939f 100644 --- a/chobun.lisp +++ b/chobun.lisp @@ -40,7 +40,7 @@ (define-step parse-tag-tree-node (first-element rest) (multiple-value-bind (args subtrees) (get-args-and-subtrees rest) - (add-code `(write-string ,(format nil "<~(~a~)~{ ~(~a~)=~s~}>" (symbol-name first-element) args) *html-stream*)) + (add-code `(format *html-stream* "<~(~a~)~{ ~(~a~)=~s~}>" ,(symbol-name first-element) `,(list ,@args))) (dolist (next-tree-node subtrees) (add-codes (parse-tree-node next-tree-node))) (add-code `(write-string ,(format nil "" (symbol-name first-element)) *html-stream*)))) @@ -51,9 +51,9 @@ ((in first-element *hoistable-special-forms*) (add-code `(,first-element ,(car rest) ,@(parse-tree-node (cadr rest))))) ((in first-element *inline-special-forms*) - (add-code `(format *html-stream* "~@[~a~]" (,first-element ,(car rest) - (progn ,@(parse-tree-node (cadr rest)) nil) - (progn ,@(parse-tree-node (caddr rest)) nil))))) + (add-code `(,first-element ,(car rest) + (progn ,@(parse-tree-node (cadr rest)) nil) + (progn ,@(parse-tree-node (caddr rest)) nil)))) (t (add-code `(format *html-stream* "~@[~a~]" (maybe-eval-html (apply #',first-element (list ,@rest)))))))) (define-step parse-list-tree-node (tree-node) @@ -79,7 +79,8 @@ (str "") (format-args nil)) (flet ((commit-curr-str () - (pushback `(format *html-stream* ,str ,@format-args) res) + (if (> (length str) 0) + (pushback `(format *html-stream* ,str ,@format-args) res)) (setf str "" format-args nil)) (append-to-str (val) (setf str (concatenate 'string str val)))) (dolist (l c) @@ -93,6 +94,12 @@ (commit-curr-str) (pushback `(dolist ,(cadr l) ,@(optimize-html-codegen (cddr l))) res)) + ((eq 'if (car l)) + (commit-curr-str) + (pushback `(if ,(cadr l) + (progn ,@(optimize-html-codegen (cddr l))) + (progn ,@(optimize-html-codegen (cdddr l)))) + res)) (t (commit-curr-str) (pushback l res)))) (commit-curr-str) @@ -149,7 +156,7 @@ The HTML tree is a nested Lisp S-Expression, each nested list can start by eithe If it's a keyword then it's interpreted as an HTML tag. For example (:div \"Hola\") is interpreted as \"
Hola
\". If it's a symbol what happens depends on the symbol, if it's one of the supported Lisp control structures, in includes that in the generated code, so it feels like using Lisp." - (let ((html-gen (optimize-html-codegen (parse-html html-tree)))) + (let ((html-gen (parse-html html-tree))) `(progn (let ((*html-stream* (make-string-output-stream))) (with-output-to-string (*html-stream*) diff --git a/t/chobun.lisp b/t/chobun.lisp new file mode 100644 index 0000000..2130076 --- /dev/null +++ b/t/chobun.lisp @@ -0,0 +1,42 @@ +(in-package :cl-user) +(defpackage chobun/test + (:use :cl :bedrock :chobun :parachute :split-sequence)) +(in-package :chobun/test) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (defun to-kebab-case (str) + (intern (format nil "~{~:@(~a~)~#[~:;-~]~}" (split-sequence #\Space str))))) + +(defmacro html-test (desc html-tree expected-output &optional (vars nil)) + (let ((test-name (to-kebab-case desc))) + `(define-test ,test-name + (let ,vars + (is string= ,expected-output (html ,html-tree)))))) + +(html-test "Single tag" (:div "Hola") "
Hola
") +(html-test "Nested tags" (:div (:span "Hola")) "
Hola
") +(html-test "Same level tags" (:div (:span "Hola") (:h1 "Title")) "
Hola

Title

") +(html-test "Tag properties" (:div :class "test" :id "wassup" (:span :id "inner" "Hola")) + "
Hola
") +(html-test "Variables" + (:div :class class-name :id "wassup" (:span :id "inner" value)) + "
Hola
" + ((class-name "test") (value "Hola"))) +(html-test "dolist" + (:div (dolist (i '(1 2 3 4)) + (:span i))) + "
1234
") +(html-test "dotimes" + (:div (dotimes (i 4) + (:span i))) + "
0123
") +(html-test "if" + (:div (if t + (:span "TRUE") + (:span "FALSE"))) + "
") +(html-test "if inside dotimes" + (:div (dotimes (i 6) + (:div (if (= (mod i 2) 0) + (:span (format nil "~a is EVEN" i)))))) + "
0 is EVEN
2 is EVEN
4 is EVEN
")