etest.el: Added start of stats.
[ETest.git] / etest-result-mode.el
blob8f2f9c59679fffdfbeab976ec7ed8fe8e4aa364d
1 ;;; etest-result-mode.el --- Watch tests pass or fail
3 ;; Copyright (C) 2008 Philip Jackson
5 ;; Author: Philip Jackson <phil@shellarchive.co.uk>
7 ;; This file is not currently part of GNU Emacs.
9 ;; This program is free software; you can redistribute it and/or
10 ;; modify it under the terms of the GNU General Public License as
11 ;; published by the Free Software Foundation; either version 2, or (at
12 ;; your option) any later version.
14 ;; This program is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program ; see the file COPYING. If not, write to
21 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
24 ;;; Commentary:
26 ;; The default result mode for etest.
28 (require 'outline)
30 (declare-function etest-resultp "etest")
32 ;; calm down byte-compiler, you can have this one...
33 (eval-when-compile
34 (defvar current-results)
35 (require 'cl))
37 ;; The grouping of the status is for convenience and use by the
38 ;; font-locking so if you change the re don't forget to capture the
39 ;; status
40 (defvar etest-rm-not-ok-re "^ *\\(not ok\\) \\.\\."
41 "Regexp that will match bad test status.")
43 (defvar etest-rm-ok-re "^ *\\(ok\\) \\.\\."
44 "Regexp that will match good test status.")
46 (defvar etest-status-re
47 (concat "\\(" etest-rm-not-ok-re
48 "\\|" etest-rm-ok-re
49 "\\)")
50 "Regexp that will match a test status.")
52 (defvar etest-rm-map
53 (let ((m (make-keymap)))
54 (define-key m (kbd "q") 'bury-buffer)
55 (define-key m (kbd "g")
56 '(lambda ()
57 (interactive)
58 (etest-rm-refresh-buffer current-results)))
59 (define-key m (kbd "#") 'etest-rm-cycle-comments)
60 (define-key m (kbd "TAB") 'etest-rm-toggle-headline)
61 (define-key m (kbd "<tab>") 'etest-rm-toggle-headline)
62 m))
64 (defvar etest-rm-comment-visibility-types
65 '(show-all show-not-ok show-ok show-none))
67 (defvar etest-rm-comment-visibility-map
68 '((show-all etest-rm-show-all-comments)
69 (show-not-ok etest-rm-hide-ok-comments)
70 (show-ok etest-rm-hide-not-ok-comments)
71 (show-none etest-rm-hide-all-comments))
72 "Defines how the result buffer should look when the user is
73 toggling visibility states.")
75 (defgroup etest nil
76 "Emacs Testing Framework"
77 :group 'lisp)
79 (defun etest-rm-count-string-at-bol (string)
80 "Count how many instances of STRING are at the start of the
81 current line."
82 (save-excursion
83 (goto-char (point-at-bol))
84 (narrow-to-region (point) (point-at-eol))
85 (let ((count 0))
86 (while (looking-at string)
87 (forward-char)
88 (setq count (1+ count)))
89 (widen)
90 count)))
92 (defun etest-rm-outline-level ()
93 "Calculate what the current outline level should be. See
94 `ouline-level' for explination."
95 ;; we add one becuase there is an extra space before a status
96 (1+ (if (looking-at etest-status-re)
97 (etest-rm-count-string-at-bol " ")
98 (etest-rm-count-string-at-bol "*"))))
100 ;;;###autoload
101 (defun etest-result-mode (&optional results)
102 "Mode used to display test results."
103 (interactive)
104 (kill-all-local-variables)
105 (setq buffer-read-only t)
106 (outline-minor-mode)
107 (set (make-local-variable 'outline-regexp)
108 (concat "\\(\\*\\|" etest-status-re "\\)"))
109 (set (make-local-variable 'outline-level)
110 'etest-rm-outline-level)
111 (set (make-local-variable 'current-results) results)
112 (setq major-mode 'etest-result-mode)
113 (setq mode-name "etest-result")
114 (set (make-local-variable 'font-lock-defaults)
115 '(etest-rm-font-lock-keywords t t))
116 (use-local-map etest-rm-map)
117 (funcall (cadr (assoc (car etest-rm-comment-visibility-types)
118 etest-rm-comment-visibility-map))))
120 (defun etest-rm-pretty-print-status (result level)
121 "The pretty printing of a single test result. "
122 (let ((returned (plist-get result :result)))
123 (let* ((doc (plist-get result :doc))
124 (comments (plist-get result :comments))
125 (prefix (if returned "ok" "not ok")))
126 (insert (concat " " prefix " "))
127 (insert-char ?\. (- 18 (length prefix) level))
128 (insert ".. ")
129 (let ((col (current-column)))
130 (insert (concat doc "\n"))
131 (when comments
132 (mapc
133 (lambda (comment)
134 (indent-to col)
135 (insert (concat "# " comment "\n")))
136 (split-string comments "\n" t)))))))
138 (defun etest-rm-pretty-print-results (results &optional level)
139 "Pretty print the results of a run to a buffer. See also
140 `etest-rm-pretty-print-status'."
141 (let ((level (or level 0))
142 (res (car results)))
143 (cond
144 ((stringp res)
145 (insert-char ?\* (1+ level))
146 (insert (concat " " res "\n"))
147 (setq level (1+ level)))
148 ((etest-resultp res)
149 (indent-to level)
150 (etest-rm-pretty-print-status res level))
151 ((listp res)
152 (etest-rm-pretty-print-results res level)))
153 (when (cdr results)
154 (etest-rm-pretty-print-results (cdr results) level))))
156 (defun etest-rm-refresh-buffer (results)
157 "Refresh the results buffer using the cached test results."
158 (save-selected-window
159 (switch-to-buffer-other-window (get-buffer-create "*etest*"))
160 (setq buffer-read-only nil)
161 (erase-buffer)
162 (etest-rm-pretty-print-results results 0)
163 (etest-result-mode results)
164 (goto-char (point-min))
165 (when (search-forward-regexp etest-rm-not-ok-re nil t)
166 (goto-char (point-at-bol)))))
168 (defconst etest-rm-not-ok-face 'etest-rm-not-ok-face)
169 (defface etest-rm-not-ok-face
170 '((default (:inherit font-lock-warning-face)))
171 "Face used for failing tests."
172 :group 'etest)
174 (defconst etest-rm-ok-face 'etest-rm-ok-face)
175 (defface etest-rm-ok-face
176 '((default (:inherit font-lock-variable-name-face)))
177 "Face used for passing tests."
178 :group 'etest)
180 (defconst etest-rm-comment-face 'etest-rm-comment-face)
181 (defface etest-rm-comment-face
182 '((default (:inherit font-lock-comment-face)))
183 "Face used for comments."
184 :group 'etes)
186 (defconst etest-rm-heading-face 'etest-rm-heading-face)
187 (defface etest-rm-heading-face
188 '((default (:inherit font-lock-keyword-face)))
189 "Face used for headings."
190 :group 'etes)
192 (defconst etest-rm-font-lock-keywords
193 `((,etest-rm-ok-re 1 etest-rm-ok-face)
194 (,etest-rm-not-ok-re 1 etest-rm-not-ok-face)
195 ("^ *\\(#.+\\)" 1 etest-rm-comment-face)
196 ("^ *\\*+ \\(.+\\)" 1 etest-rm-heading-face)))
198 (defun etest-rm-toggle-headline ()
199 "Toggle the visibility of a test category."
200 (interactive)
201 (unless (looking-at outline-regexp)
202 (outline-previous-heading))
203 (if (get-char-property (point-at-eol) 'invisible)
204 (show-subtree)
205 (hide-subtree)))
207 ;;; comment toggling etc...
209 (defun etest-rm-cycle-comments ()
210 "Shift the values in `etest-rm-comment-visibility-types' and
211 use the `car' of that list to determine the visibility of
212 comments."
213 (interactive)
214 (setq etest-rm-comment-visibility-types
215 (concatenate 'list
216 (cdr etest-rm-comment-visibility-types)
217 (list (car etest-rm-comment-visibility-types))))
218 (etest-rm-refresh-buffer current-results)
219 (message (format "%S" (car etest-rm-comment-visibility-types))))
221 (defmacro etest-with-comments (&rest body)
222 "Eval BODY on each comment in the results buffer."
223 `(save-excursion
224 (goto-char (point-min))
225 (while (search-forward-regexp etest-status-re nil t)
226 (outline-previous-heading)
227 ,@body
228 (forward-line))))
230 (defun etest-rm-hide-not-ok-comments ()
231 "Hide all comments associated with a passing test in a result
232 buffer."
233 (interactive)
234 (etest-with-comments
235 (if (looking-at etest-rm-not-ok-re)
236 (hide-subtree)
237 (show-subtree))))
239 (defun etest-rm-hide-ok-comments ()
240 "Hide all comments associated with a passing test in a result
241 buffer."
242 (interactive)
243 (etest-with-comments
244 (if (looking-at etest-rm-ok-re)
245 (hide-subtree)
246 (show-subtree))))
248 (defun etest-rm-hide-all-comments ()
249 "Hide all comments in a result buffer."
250 (interactive)
251 (etest-with-comments
252 (hide-subtree)))
254 (defun etest-rm-show-all-comments ()
255 "Show all comments in a result buffer."
256 (interactive)
257 (etest-with-comments
258 (show-subtree)))
260 (provide 'etest-result-mode)