From fe6c3e528eece3ae397575413fdd0dddee202e13 Mon Sep 17 00:00:00 2001 From: ikappaki Date: Sun, 14 May 2023 22:21:24 +0100 Subject: [PATCH] Run tests from source, intro bbin integration tests Also extend test suite to MS-Win. --- .github/workflows/test.yml | 23 ++++------- clj2el.el | 20 ++++++++-- test/integration-tests.el | 66 +++++++++++++++++++++++++++++++ test/test.el | 81 +++++++++++++++++++++++++++++++------- 4 files changed, 156 insertions(+), 34 deletions(-) create mode 100644 test/integration-tests.el diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0229bf3..d8eebae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,8 +8,8 @@ jobs: strategy: matrix: - os: [ubuntu-latest, macos-latest] - emacs_version: ["27.2", "28.1"] + os: [macos-latest, ubuntu-latest, windows-latest] + emacs_version: ["27.2", "28.2"] include: - os: ubuntu-latest emacs_version: "snapshot" @@ -27,6 +27,10 @@ jobs: cli: latest bb: latest + - name: Prime babashka + run: | + bb clojure --help + - name: Set up Emacs if: "!startsWith (matrix.os, 'windows')" uses: purcell/setup-emacs@master @@ -63,19 +67,7 @@ jobs: scoop bucket add extras scoop bucket add scoop-clojure https://github.com/littleli/scoop-clojure scoop install bbin - - - name: Install clj2el as executable - if: "!startsWith (matrix.os, 'windows')" - run: bbin install . - - - name: Install clj2el as executable - if: startsWith (matrix.os, 'windows') - run: | - iex "& {$(irm get.scoop.sh)} -RunAsAdmin" - scoop bucket add extras - scoop bucket add scoop-clojure https://github.com/littleli/scoop-clojure - scoop install bbin - bbin install . + get-command bbin.cmd | split-path -parent | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Install Eldev if: "!startsWith (matrix.os, 'windows')" @@ -88,5 +80,4 @@ jobs: - name: Test the project run: | - export PATH="$PATH:$HOME/.babashka/bbin/bin" eldev -dtT test diff --git a/clj2el.el b/clj2el.el index 585d509..df145e7 100644 --- a/clj2el.el +++ b/clj2el.el @@ -18,22 +18,35 @@ ;; ;;; Code: +(defcustom clj2el-command + "clj2el" + "The command used to execute clj2el." + :type 'string + :group 'clj2el) + (defun clj2el-transpile-buffer () (interactive) - (shell-command-on-region (point-min) (point-max) "clj2el" (current-buffer))) + (shell-command-on-region (point-min) (point-max) clj2el-command (current-buffer))) (defun clj2el-transpile-region () (interactive) - (shell-command-on-region (point) (mark) "clj2el" (current-buffer) 't)) + (shell-command-on-region (point) (mark) clj2el-command (current-buffer) 't)) (defmacro clj2el-clj! (expr) + "Transpile clojure like EXPR form to elisp and eval it. + +Transpilation is performed by sending EXPR as input to +`clj2el-command'. Signals an error if the program cannot be find +or an error is reported." (let* ((expr-as-string (prin1-to-string expr)) (temp-buf "*el2clj-work*")) (get-buffer-create temp-buf) (let* ((elisp-code (with-current-buffer temp-buf (erase-buffer) (insert expr-as-string) - (shell-command-on-region (point-min) (point-max) "clj2el" temp-buf) + (when (not (= (shell-command-on-region (point-min) (point-max) clj2el-command temp-buf) 0)) + (error ":clj23el-clj!-cmd-error :clj2el-command %S :error %s" + clj2el-command (buffer-substring-no-properties (point-min) (point-max)))) (buffer-substring (point-min) (point-max)))) (read (read-from-string elisp-code)) (expr (car read))) @@ -43,6 +56,7 @@ (&rest _exprs)) (clj2el-comment + (setq clj2el-command "bb -x clj2el.exec/exec") (clj2el-clj! (do (defn foo [x] (inc x)) (defn bar [x] (inc x)))) diff --git a/test/integration-tests.el b/test/integration-tests.el new file mode 100644 index 0000000..35f910e --- /dev/null +++ b/test/integration-tests.el @@ -0,0 +1,66 @@ +(require 'clj2el) + +(require 'cl-lib) +(require 'ert) + +(defmacro with-temp-bbin-install (&rest body) + "Create a temp dir to install clj2el to with bbin and run BODY. + +The following functions are updated in BODY to use this installation + +- `clj2el-clj!' +- `clj2el-transpile-buffer' (also called interactively with prefix arg) +- `clj2el-transpile-range' (also called interactively with prefix arg)." + (declare (indent 0)) + `(let ((bbin-install-dir (make-temp-file "clj2el" t)) + (bbin-exec (executable-find "bbin")) + (env-bbd (getenv "BABASHKA_BBIN_DIR")) + (env-path (getenv "PATH"))) + ;; (message ":temp-bbin-install-dir-created-at %s" bbin-install-dir) + (unwind-protect + (progn + (should bbin-exec) + (setenv "BABASHKA_BBIN_DIR" bbin-install-dir) + (setenv "PATH" (concat (expand-file-name "bin" bbin-install-dir) path-separator + (getenv "PATH"))) + (with-temp-buffer + (let ((ret (call-process-shell-command "bbin" nil (current-buffer) nil + "install" "."))) + (when (not (= ret 0)) + (message ":bbin-install-error %s" (buffer-substring-no-properties (point-min) (point-max)))) + (should (= ret 0)))) + (cl-macrolet ((clj2el-clj! (expr) `(eval '(clj2el-clj! ,expr))) + (clj2el-transpile-buffer () '(let ((current-prefix-arg '(4))) + (call-interactively 'clj2el-transpile-buffer))) + (clj2el-transpile-range () '(let ((current-prefix-arg '(4))) + (call-interactively 'clj2el-transpile-range)))) + ,@body)) + (progn + (setenv "BABASHKA_BBIN_DIR" env-bbd) + (setenv "PATH" env-path) + ;; (message ":temp-bbin-install-deleting... %s" bbin-install-dir) + (delete-directory bbin-install-dir t))))) + + +(ert-deftest integration () + (with-temp-bbin-install + + ;; clj2el-transpile-buffer + (should (string= "(1+ 3)\n" + (with-temp-buffer + (insert "(inc 3)") + (clj2el-transpile-buffer) + (buffer-substring-no-properties (point-min) (point-max))))) + + ;; clj2el-transpile-region + (should (string= "[[ (1+ 4)\n ]]" + (with-temp-buffer + (insert "[[ (inc 4) ]]") + (set-mark 4) + (goto-char 11) + (clj2el-transpile-region) + (buffer-substring-no-properties (point-min) (point-max))))) + + + ;; clj2el-clj! + (should (= 6 (clj2el-clj! (inc 5)))))) diff --git a/test/test.el b/test/test.el index 1ac4f33..1979bb8 100644 --- a/test/test.el +++ b/test/test.el @@ -1,18 +1,69 @@ (require 'clj2el) +(require 'cl-lib) +(require 'ert) + +(cl-defmacro with-clj2el-test (&rest body &aux (test-clj2el-command "bb -x clj2el.exec/exec")) + "Execute BODY with `clj2el-command' bound to TEST-CLJ2EL-COMMAND. + +The command is supposed to execute clj2el from source. + +the following fucntions are also updated to be called interactively with a prefix arg: +- `clj2el-transpile-buffer' +- `clj2el-transpile-range'." + (declare (indent 0)) + `(let ((clj2el-command ,test-clj2el-command)) + (cl-macrolet (;; use eval to pick up the updated + ;; `clj2el-command'. + (clj2el-clj! (expr) `(eval '(clj2el-clj! ,expr))) + + ;; call with prefix arg. + (clj2el-transpile-buffer () '(let ((current-prefix-arg '(4))) + (call-interactively 'clj2el-transpile-buffer))) + (clj2el-transpile-range () '(let ((current-prefix-arg '(4))) + (call-interactively 'clj2el-transpile-range)))) + ,@body))) + +(ert-deftest basic () + (with-clj2el-test + + ;; clj2el-transpile-buffer + (should (string= "(1+ 2)\n" + (with-temp-buffer + (insert "(inc 2)") + (clj2el-transpile-buffer) + (buffer-substring-no-properties (point-min) (point-max))))) + + ;; clj2el-transpile-region + (should (string= "[[ (1+ 2)\n ]]" + (with-temp-buffer + (insert "[[ (inc 2) ]]") + (set-mark 4) + (goto-char 11) + (clj2el-transpile-region) + ;; (test--call-interactively-with-prefix 'clj2el-transpile-region) + (buffer-substring-no-properties (point-min) (point-max))))) + + + ;; clj2el-clj! + (should (= 3 (clj2el-clj! (inc 2)))))) + (ert-deftest juxt () - (should (equal - (clj2el-clj! ((juxt inc dec) 1)) - '(2 0))) - (should (equal - (clj2el-clj! ((juxt + -) - 0 1 2 3 4 5)) - '(15 -15))) - ;; Currently, `funcall' is required here. Might change in the future. - (should (equal - (clj2el-clj! (let [fns (juxt + -)] - (funcall fns 0 1 2 3 4 5))) - '(15 -15))) - ;; Missing `funcall' - (should-error (clj2el-clj! (let [fns (juxt + -)] - (fns 0 1 2 3 4 5))))) + (with-clj2el-test + (should (equal + (clj2el-clj! ((juxt inc dec) 1)) + '(2 0))) + (should (equal + (clj2el-clj! ((juxt + -) + 0 1 2 3 4 5)) + '(15 -15))) + ;; Currently, `funcall' is required here. Might change in the future. + + (should (equal + (clj2el-clj! (let [fns (juxt + -)] + (funcall fns 0 1 2 3 4 5))) + '(15 -15))) + ;; Missing `funcall' + + (should-error (clj2el-clj! (let [fns (juxt + -)] + (fns 0 1 2 3 4 5))))))