org-test.el 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. ;;;; org-test.el --- Tests for Org-mode
  2. ;; Copyright (c) 2010 Sebastian Rose, Eric Schulte
  3. ;; Authors:
  4. ;; Sebastian Rose, Hannover, Germany, sebastian_rose gmx de
  5. ;; Eric Schulte, Santa Fe, New Mexico, USA, schulte.eric gmail com
  6. ;; David Maus, Brunswick, Germany, dmaus ictsoc de
  7. ;; Released under the GNU General Public License version 3
  8. ;; see: http://www.gnu.org/licenses/gpl-3.0.html
  9. ;; Definition of `special-mode' copied from Emacs23's simple.el to be
  10. ;; provide a testing environment for Emacs22.
  11. ;;;; Comments:
  12. ;; Interactive testing for Org mode.
  13. ;; The heart of all this is the commands `org-test-current-defun'. If
  14. ;; called while in a `defun' all ert tests with names matching the
  15. ;; name of the function are run.
  16. ;;; Test Development
  17. ;; For test development purposes a number of navigation and test
  18. ;; function construction routines are available as a git submodule
  19. ;; (jump.el)
  20. ;; Install with...
  21. ;; $ git submodule init
  22. ;; $ git submodule update
  23. ;;;; Code:
  24. (let* ((org-test-dir (expand-file-name
  25. (file-name-directory
  26. (or load-file-name buffer-file-name))))
  27. (org-lisp-dir (expand-file-name
  28. (concat org-test-dir "../lisp"))))
  29. (unless (featurep 'org)
  30. (setq load-path (cons org-lisp-dir load-path))
  31. (require 'org)
  32. (org-babel-do-load-languages
  33. 'org-babel-load-languages '((sh . t))))
  34. (let* ((load-path (cons
  35. org-test-dir
  36. (cons
  37. (expand-file-name "jump" org-test-dir)
  38. load-path))))
  39. (require 'cl)
  40. (when (= emacs-major-version 22)
  41. (defvar special-mode-map
  42. (let ((map (make-sparse-keymap)))
  43. (suppress-keymap map)
  44. (define-key map "q" 'quit-window)
  45. (define-key map " " 'scroll-up)
  46. (define-key map "\C-?" 'scroll-down)
  47. (define-key map "?" 'describe-mode)
  48. (define-key map "h" 'describe-mode)
  49. (define-key map ">" 'end-of-buffer)
  50. (define-key map "<" 'beginning-of-buffer)
  51. (define-key map "g" 'revert-buffer)
  52. (define-key map "z" 'kill-this-buffer)
  53. map))
  54. (put 'special-mode 'mode-class 'special)
  55. (define-derived-mode special-mode nil "Special"
  56. "Parent major mode from which special major modes should inherit."
  57. (setq buffer-read-only t)))
  58. (require 'ert)
  59. (require 'ert-x)
  60. (when (file-exists-p
  61. (expand-file-name "jump/jump.el" org-test-dir))
  62. (require 'jump)
  63. (require 'which-func))))
  64. (defconst org-test-default-test-file-name "tests.el"
  65. "For each defun a separate file with tests may be defined.
  66. tests.el is the fallback or default if you like.")
  67. (defconst org-test-default-directory-name "testing"
  68. "Basename or the directory where the tests live.
  69. org-test searches this directory up the directory tree.")
  70. (defconst org-test-dir
  71. (expand-file-name (file-name-directory (or load-file-name buffer-file-name))))
  72. (defconst org-base-dir
  73. (expand-file-name ".." org-test-dir))
  74. (defconst org-test-example-dir
  75. (expand-file-name "examples" org-test-dir))
  76. (defconst org-test-file
  77. (expand-file-name "normal.org" org-test-example-dir))
  78. (defconst org-test-no-heading-file
  79. (expand-file-name "no-heading.org" org-test-example-dir))
  80. (defconst org-test-link-in-heading-file
  81. (expand-file-name "link-in-heading.org" org-test-dir))
  82. ;; Errors used by test files that shouldn't be run because local
  83. ;; dependencies are missing.
  84. (put 'org-exe-not-found
  85. 'error-conditions
  86. '(error org-test-missing-dependency org-test-exe-not-found))
  87. (put 'org-lib-not-found
  88. 'error-conditions
  89. '(error org-test-missing-dependency org-test-lib-not-found))
  90. ;;; Functions for writing tests
  91. (defun org-test-for-executable (exe)
  92. "Throw an error if EXE is not available.
  93. This can be used at the top of code-block-language specific test
  94. files to avoid loading the file on systems without the
  95. executable."
  96. (unless (> (length (shell-command-to-string (format "which %s" exe))) 0)
  97. (signal 'org-test-exe-not-found exe)))
  98. (defun org-test-buffer (&optional file)
  99. "TODO: Setup and return a buffer to work with.
  100. If file is non-nil insert it's contents in there.")
  101. (defun org-test-compare-with-file (&optional file)
  102. "TODO: Compare the contents of the test buffer with FILE.
  103. If file is not given, search for a file named after the test
  104. currently executed.")
  105. (defmacro org-test-at-id (id &rest body)
  106. "Run body after placing the point in the headline identified by ID."
  107. (declare (indent 1))
  108. `(let* ((id-location (org-id-find ,id))
  109. (id-file (car id-location))
  110. (visited-p (get-file-buffer id-file))
  111. to-be-removed)
  112. (save-window-excursion
  113. (save-match-data
  114. (org-id-goto ,id)
  115. (setq to-be-removed (current-buffer))
  116. (condition-case nil
  117. (progn
  118. (org-show-subtree)
  119. (org-show-block-all))
  120. (error nil))
  121. (save-restriction ,@body)))
  122. (unless visited-p
  123. (kill-buffer to-be-removed))))
  124. (defmacro org-test-in-example-file (file &rest body)
  125. "Execute body in the Org-mode example file."
  126. (declare (indent 1))
  127. `(let* ((my-file (or ,file org-test-file))
  128. (visited-p (get-file-buffer my-file))
  129. to-be-removed)
  130. (save-window-excursion
  131. (save-match-data
  132. (find-file my-file)
  133. (setq to-be-removed (current-buffer))
  134. (goto-char (point-min))
  135. (condition-case nil
  136. (progn
  137. (outline-next-visible-heading 1)
  138. (org-show-subtree)
  139. (org-show-block-all))
  140. (error nil))
  141. (save-restriction ,@body)))
  142. (unless visited-p
  143. (kill-buffer to-be-removed))))
  144. (defmacro org-test-at-marker (file marker &rest body)
  145. "Run body after placing the point at MARKER in FILE.
  146. Note the uuidgen command-line command can be useful for
  147. generating unique markers for insertion as anchors into org
  148. files."
  149. (declare (indent 2))
  150. `(org-test-in-example-file ,file
  151. (goto-char (point-min))
  152. (re-search-forward (regexp-quote ,marker))
  153. ,@body))
  154. (defmacro org-test-with-temp-text (text &rest body)
  155. "Run body in a temporary buffer with Org-mode as the active
  156. mode holding TEXT. If the string \"<point>\" appears in TEXT
  157. then remove it and place the point there before running BODY."
  158. (declare (indent 1))
  159. (let ((inside-text (if (stringp text) text (eval text))))
  160. `(with-temp-buffer
  161. (org-mode)
  162. ,(let ((point (string-match (regexp-quote "<point>") inside-text)))
  163. (if point
  164. `(progn (insert `(replace-match "" nil nil inside-text))
  165. (goto-char ,(match-beginning 0)))
  166. `(progn (insert ,inside-text)
  167. (goto-char (point-min)))))
  168. ,@body)))
  169. ;;; Navigation Functions
  170. (when (featurep 'jump)
  171. (defjump org-test-jump
  172. (("lisp/\\1.el" . "testing/lisp/test-\\1.el")
  173. ("lisp/\\1.el" . "testing/lisp/\\1.el/test.*.el")
  174. ("contrib/lisp/\\1.el" . "testing/contrib/lisp/test-\\1.el")
  175. ("contrib/lisp/\\1.el" . "testing/contrib/lisp/\\1.el/test.*.el")
  176. ("testing/lisp/test-\\1.el" . "lisp/\\1.el")
  177. ("testing/lisp/\\1.el" . "lisp/\\1.el/test.*.el")
  178. ("testing/contrib/lisp/test-\\1.el" . "contrib/lisp/\\1.el")
  179. ("testing/contrib/lisp/test-\\1.el" . "contrib/lisp/\\1.el/test.*.el"))
  180. (concat org-base-dir "/")
  181. "Jump between org-mode files and their tests."
  182. (lambda (path)
  183. (let* ((full-path (expand-file-name path org-base-dir))
  184. (file-name (file-name-nondirectory path))
  185. (name (file-name-sans-extension file-name)))
  186. (find-file full-path)
  187. (insert
  188. ";;; " file-name "\n\n"
  189. ";; Copyright (c) " (nth 5 (decode-time (current-time)))
  190. " " user-full-name "\n"
  191. ";; Authors: " user-full-name "\n\n"
  192. ";; Released under the GNU General Public License version 3\n"
  193. ";; see: http://www.gnu.org/licenses/gpl-3.0.html\n\n"
  194. ";;;; Comments:\n\n"
  195. ";; Template test file for Org-mode tests\n\n"
  196. " \n"
  197. ";;; Code:\n"
  198. "(let ((load-path (cons (expand-file-name\n"
  199. " \"..\" (file-name-directory\n"
  200. " (or load-file-name buffer-file-name)))\n"
  201. " load-path)))\n"
  202. " (require 'org-test)\n"
  203. " (require 'org-test-ob-consts))\n\n"
  204. " \n"
  205. ";;; Tests\n"
  206. "(ert-deftest " name "/example-test ()\n"
  207. " \"Just an example to get you started.\"\n"
  208. " (should t)\n"
  209. " (should-not nil)\n"
  210. " (should-error (error \"errr...\")))\n\n\n"
  211. "(provide '" name ")\n\n"
  212. ";;; " file-name " ends here\n") full-path))
  213. (lambda () ((lambda (res) (if (listp res) (car res) res)) (which-function)))))
  214. (define-key emacs-lisp-mode-map "\M-\C-j" 'org-test-jump)
  215. ;;; Miscellaneous helper functions
  216. (defun org-test-strip-text-props (s)
  217. "Return S without any text properties."
  218. (let ((noprop (copy-sequence s)))
  219. (set-text-properties 0 (length noprop) nil noprop)
  220. noprop))
  221. (defun org-test-string-exact-match (regex string &optional start)
  222. "case sensative string-match"
  223. (let ((case-fold-search nil)
  224. (case-replace nil))
  225. (if(and (equal regex "")
  226. (not(equal string "")))
  227. nil
  228. (if (equal 0 (string-match regex string start))
  229. t
  230. nil))))
  231. ;;; Load and Run tests
  232. (defun org-test-load ()
  233. "Load up the org-mode test suite."
  234. (interactive)
  235. (flet ((rld (base)
  236. ;; Recursively load all files, if files throw errors
  237. ;; then silently ignore the error and continue to the
  238. ;; next file. This allows files to error out if
  239. ;; required executables aren't available.
  240. (mapc
  241. (lambda (path)
  242. (if (file-directory-p path)
  243. (rld path)
  244. (condition-case nil
  245. (load-file path)
  246. (org-exe-not-found nil))))
  247. (directory-files base 'full
  248. "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*\\.el$"))))
  249. (rld (expand-file-name "lisp" org-test-dir))
  250. (rld (expand-file-name "lisp" (expand-file-name "contrib" org-test-dir)))))
  251. (defun org-test-current-defun ()
  252. "Test the current function."
  253. (interactive)
  254. (ert (which-function)))
  255. (defun org-test-current-file ()
  256. "Run all tests for current file."
  257. (interactive)
  258. (ert (concat "test-"
  259. (file-name-sans-extension
  260. (file-name-nondirectory (buffer-file-name)))
  261. "/")))
  262. (defun org-test-touch-all-examples ()
  263. (dolist (file (directory-files
  264. org-test-example-dir 'full
  265. "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*\\.org$"))
  266. (find-file file)))
  267. (defun org-test-run-batch-tests ()
  268. "Run all defined tests matching \"\\(org\\|ob\\)\".
  269. Load all test files first."
  270. (interactive)
  271. (org-test-touch-all-examples)
  272. (org-test-load)
  273. (ert-run-tests-batch-and-exit "\\(org\\|ob\\)"))
  274. (defun org-test-run-all-tests ()
  275. "Run all defined tests matching \"\\(org\\|ob\\)\".
  276. Load all test files first."
  277. (interactive)
  278. (org-test-touch-all-examples)
  279. (org-test-load)
  280. (ert "\\(org\\|ob\\)"))
  281. (provide 'org-test)
  282. ;;; org-test.el ends here