Skip to content

Instantly share code, notes, and snippets.

@twlz0ne
Created April 20, 2019 12:41
Show Gist options
  • Save twlz0ne/df985c6c9eb26f318e2c382242cadd9a to your computer and use it in GitHub Desktop.
Save twlz0ne/df985c6c9eb26f318e2c382242cadd9a to your computer and use it in GitHub Desktop.
Start a #emacs in a subprocess, and execute expressions there.
;;; test-with-emacs-v1.el --- Test with-emacs v1 -*- lexical-binding: t; -*-
;; Author: [email protected]
;; Usage: emacs --batch -l ~/.scratch/emacs/test-with-emacs-v1.el -f ert-run-tests-batch-and-exit
;; Date: 2019/04/20
;;; Code:
(require 'ert)
(defmacro with-emacs (path &rest body)
"Start a emacs in a subprocess, and execute BODY there.
PATH is the abs path of emacs executable."
(declare (indent defun) (debug t))
`(let* ((errorcode)
(command
(mapconcat
'identity
(list
,path
"--batch"
"--eval"
(format "'(funcall (eval (read (base64-decode-string %S))))'"
(base64-encode-string ;; Inspired by `async-start'
(format
"#'%S"
(lambda nil
,@body))))) " "))
(output
(funcall
(lambda (suffix s)
;; Taken from `s-chop-suffix', for Emacs 24.3 or lower
(let ((pos (- (length suffix))))
(if (and (>= (length s) (length suffix))
(string= suffix (substring s pos)))
(substring s 0 pos)
s)))
"\n"
(with-output-to-string
(with-current-buffer standard-output
(setq errcode (call-process-shell-command command nil standard-output)))))))
(if (zerop errcode)
output
(signal 'error (list output)))))
;;; Use cases
;; --------------------------------------------------------------------------------
;; Determine if a function exists in a specific version of Emacs
(ert-deftest test-with-emacs--string-suffix-p-does-not-exists-in-emacs-24-3 ()
(should
(equal "nil"
(with-emacs "/Applications/Emacs-24.3.app/Contents/MacOS/Emacs"
(message "%s" (fboundp 'string-suffix-p))))))
;; --------------------------------------------------------------------------------
;; Get doc string from a specific version of Emacs
(ert-deftest test-with-emacs--get-doc-strig-from-a-specific-version-of-emacs ()
(should
(equal "assoc is a built-in function in `C source code'.
(assoc KEY LIST)
Return non-nil if KEY is `equal' to the car of an element of LIST.
The value is actually the first element of LIST whose car equals KEY.
"
(with-emacs "/Applications/Emacs-24.4.app/Contents/MacOS/Emacs"
(unless (fboundp 'elisp--company-doc-buffer)
(defun elisp--company-doc-buffer (str)
(let ((symbol (intern-soft str)))
;; FIXME: we really don't want to "display-buffer and then undo it".
(save-window-excursion
;; Make sure we don't display it in another frame, otherwise
;; save-window-excursion won't be able to undo it.
(let ((display-buffer-overriding-action
'(nil . ((inhibit-switch-frame . t)))))
(ignore-errors
(cond
((fboundp symbol) (describe-function symbol))
((boundp symbol) (describe-variable symbol))
((featurep symbol) (describe-package symbol))
((facep symbol) (describe-face symbol))
(t (signal 'user-error nil)))
(help-buffer)
))))))
;; avoid help buttons
(defun help-window-display-message (quit-part window &optional scroll) nil)
(message "%s" (with-current-buffer (elisp--company-doc-buffer "assoc")
(buffer-substring-no-properties (point-min)
(point-max))))))))
;; --------------------------------------------------------------------------------
;; Run test code in a separate Emacs process (like a sandbox)
(defun greet (name)
(message "Hello, %s" name))
(ert-deftest test-with-emacs--run-test-code-in-a-separate-emacs-process-like-a-sandbox ()
(should
(equal "Hi, Tom"
(with-emacs "/Applications/Emacs-26.2.app/Contents/MacOS/Emacs"
(defun greet (name)
(message "Hi, %s" name))
(greet "Tom"))))
(should
(equal "Hello, Tom"
(greet "Tom"))))
;;; test-with-emacs-v1.el ends here
@twlz0ne
Copy link
Author

twlz0ne commented Apr 20, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment