org-test.el 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. ;; Released under the GNU General Public License version 3
  7. ;; see: http://www.gnu.org/licenses/gpl-3.0.html
  8. ;;;; Comments:
  9. ;; Interactive testing for Org mode.
  10. ;; The heart of all this is the commands `org-test-current-defun'. If
  11. ;; called while in a `defun' all ert tests with names matching the
  12. ;; name of the function are run.
  13. ;;; Test Development
  14. ;; For test development purposes a number of navigation and test
  15. ;; function construction routines are available as a git submodule
  16. ;; (jump.el)
  17. ;; Install with...
  18. ;; $ git submodule init
  19. ;; $ git submodule update
  20. ;;;; Code:
  21. (let ((org-test-dir (expand-file-name
  22. (file-name-directory
  23. (or load-file-name buffer-file-name)))))
  24. (let ((org-lisp-dir (expand-file-name
  25. (concat org-test-dir "../lisp"))))
  26. (unless (member 'features "org")
  27. (setq load-path (cons org-lisp-dir load-path))
  28. (org-babel-do-load-languages
  29. 'org-babel-load-languages '((sh . t)))))
  30. (let* ((load-path (cons
  31. (expand-file-name "ert" org-test-dir)
  32. (cons
  33. (expand-file-name "jump" org-test-dir)
  34. load-path))))
  35. (require 'cl)
  36. (require 'ert)
  37. (require 'ert-x)
  38. (when (file-exists-p
  39. (expand-file-name "jump/jump.el" org-test-dir))
  40. (require 'jump)
  41. (require 'which-func))
  42. (require 'org)))
  43. (defconst org-test-default-test-file-name "tests.el"
  44. "For each defun a separate file with tests may be defined.
  45. tests.el is the fallback or default if you like.")
  46. (defconst org-test-default-directory-name "testing"
  47. "Basename or the directory where the tests live.
  48. org-test searches this directory up the directory tree.")
  49. (defconst org-test-dir
  50. (expand-file-name (file-name-directory (or load-file-name buffer-file-name))))
  51. (defconst org-base-dir
  52. (expand-file-name ".." org-test-dir))
  53. (defconst org-test-example-dir
  54. (expand-file-name "examples" org-test-dir))
  55. (defconst org-test-file
  56. (expand-file-name "normal.org" org-test-example-dir))
  57. (defconst org-test-no-heading-file
  58. (expand-file-name "no-heading.org" org-test-example-dir))
  59. (defconst org-test-link-in-heading-file
  60. (expand-file-name "link-in-heading.org" org-test-dir))
  61. ;;; Functions for writing tests
  62. (defun org-test-buffer (&optional file)
  63. "TODO: Setup and return a buffer to work with.
  64. If file is non-nil insert it's contents in there.")
  65. (defun org-test-compare-with-file (&optional file)
  66. "TODO: Compare the contents of the test buffer with FILE.
  67. If file is not given, search for a file named after the test
  68. currently executed.")
  69. (defmacro org-test-at-id (id &rest body)
  70. "Run body after placing the point in the headline identified by ID."
  71. (declare (indent 1))
  72. `(let* ((id-location (org-id-find ,id))
  73. (id-file (car id-location))
  74. (visited-p (get-file-buffer id-file))
  75. to-be-removed)
  76. (save-window-excursion
  77. (save-match-data
  78. (org-id-goto ,id)
  79. (setq to-be-removed (current-buffer))
  80. (condition-case nil
  81. (progn
  82. (org-show-subtree)
  83. (org-show-block-all))
  84. (error nil))
  85. (save-restriction ,@body)))
  86. (unless visited-p
  87. (kill-buffer to-be-removed))))
  88. (defmacro org-test-in-example-file (file &rest body)
  89. "Execute body in the Org-mode example file."
  90. (declare (indent 1))
  91. `(let* ((my-file (or ,file org-test-file))
  92. (visited-p (get-file-buffer my-file))
  93. to-be-removed)
  94. (save-window-excursion
  95. (save-match-data
  96. (find-file my-file)
  97. (setq to-be-removed (current-buffer))
  98. (goto-char (point-min))
  99. (condition-case nil
  100. (progn
  101. (outline-next-visible-heading 1)
  102. (org-show-subtree)
  103. (org-show-block-all))
  104. (error nil))
  105. (save-restriction ,@body)))
  106. (unless visited-p
  107. (kill-buffer to-be-removed))))
  108. (defmacro org-test-at-marker (file marker &rest body)
  109. "Run body after placing the point at MARKER in FILE.
  110. Note the uuidgen command-line command can be useful for
  111. generating unique markers for insertion as anchors into org
  112. files."
  113. (declare (indent 2))
  114. `(org-test-in-example-file ,file
  115. (goto-char (point-min))
  116. (re-search-forward (regexp-quote ,marker))
  117. ,@body))
  118. ;;; Navigation Functions
  119. (when (featurep 'jump)
  120. (defjump org-test-jump
  121. (("lisp/\\1.el" . "testing/lisp/test-\\1.el")
  122. ("lisp/\\1.el" . "testing/lisp/\\1.el/test.*.el")
  123. ("contrib/lisp/\\1.el" . "testing/contrib/lisp/test-\\1.el")
  124. ("contrib/lisp/\\1.el" . "testing/contrib/lisp/\\1.el/test.*.el")
  125. ("testing/lisp/test-\\1.el" . "lisp/\\1.el")
  126. ("testing/lisp/\\1.el" . "lisp/\\1.el/test.*.el")
  127. ("testing/contrib/lisp/test-\\1.el" . "contrib/lisp/\\1.el")
  128. ("testing/contrib/lisp/test-\\1.el" . "contrib/lisp/\\1.el/test.*.el"))
  129. (concat org-base-dir "/")
  130. "Jump between org-mode files and their tests."
  131. (lambda (path)
  132. (let* ((full-path (expand-file-name path org-base-dir))
  133. (file-name (file-name-nondirectory path))
  134. (name (file-name-sans-extension file-name)))
  135. (find-file full-path)
  136. (insert
  137. ";;; " file-name "\n\n"
  138. ";; Copyright (c) " (nth 5 (decode-time (current-time)))
  139. " " user-full-name "\n"
  140. ";; Authors: " user-full-name "\n\n"
  141. ";; Released under the GNU General Public License version 3\n"
  142. ";; see: http://www.gnu.org/licenses/gpl-3.0.html\n\n"
  143. ";;;; Comments:\n\n"
  144. ";; Template test file for Org-mode tests\n\n"
  145. " \n"
  146. ";;; Code:\n"
  147. "(let ((load-path (cons (expand-file-name\n"
  148. " \"..\" (file-name-directory\n"
  149. " (or load-file-name buffer-file-name)))\n"
  150. " load-path)))\n"
  151. " (require 'org-test)\n"
  152. " (require 'org-test-ob-consts))\n\n"
  153. " \n"
  154. ";;; Tests\n"
  155. "(ert-deftest " name "/example-test ()\n"
  156. " \"Just an example to get you started.\"\n"
  157. " (should t)\n"
  158. " (should-not nil)\n"
  159. " (should-error (error \"errr...\")))\n\n\n"
  160. "(provide '" name ")\n\n"
  161. ";;; " file-name " ends here\n") full-path))
  162. (lambda () ((lambda (res) (if (listp res) (car res) res)) (which-function)))))
  163. (define-key emacs-lisp-mode-map "\M-\C-j" 'org-test-jump)
  164. ;;; Miscellaneous helper functions
  165. (defun org-test-strip-text-props (s)
  166. "Return S without any text properties."
  167. (let ((noprop (copy-sequence s)))
  168. (set-text-properties 0 (length noprop) nil noprop)
  169. noprop))
  170. (defun org-test-string-exact-match (regex string &optional start)
  171. "case sensative string-match"
  172. (let ((case-fold-search nil)
  173. (case-replace nil))
  174. (if(and (equal regex "")
  175. (not(equal string "")))
  176. nil
  177. (if (equal 0 (string-match regex string start))
  178. t
  179. nil))))
  180. ;;; Load and Run tests
  181. (defun org-test-load ()
  182. "Load up the org-mode test suite."
  183. (interactive)
  184. (flet ((rload (base)
  185. (mapc
  186. (lambda (path)
  187. (if (file-directory-p path) (rload path) (load-file path)))
  188. (directory-files base 'full
  189. "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*\\.el$"))))
  190. (rload (expand-file-name "lisp" org-test-dir))
  191. (rload (expand-file-name "lisp"
  192. (expand-file-name "contrib" org-test-dir)))))
  193. (defun org-test-current-defun ()
  194. "Test the current function."
  195. (interactive)
  196. (ert (which-function)))
  197. (defun org-test-current-file ()
  198. "Run all tests for current file."
  199. (interactive)
  200. (ert (concat "test-"
  201. (file-name-sans-extension
  202. (file-name-nondirectory (buffer-file-name)))
  203. "/")))
  204. (defun org-test-touch-all-examples ()
  205. (dolist (file (directory-files
  206. org-test-example-dir 'full
  207. "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*\\.org$"))
  208. (find-file file)))
  209. (defun org-test-run-batch-tests ()
  210. "Run all defined tests matching \"\\(org\\|ob\\)\".
  211. Load all test files first."
  212. (interactive)
  213. (org-test-touch-all-examples)
  214. (org-test-load)
  215. (ert-run-tests-batch-and-exit "\\(org\\|ob\\)"))
  216. (defun org-test-run-all-tests ()
  217. "Run all defined tests matching \"\\(org\\|ob\\)\".
  218. Load all test files first."
  219. (interactive)
  220. (org-test-touch-all-examples)
  221. (org-test-load)
  222. (ert "\\(org\\|ob\\)"))
  223. (provide 'org-test)
  224. ;;; org-test.el ends here