emacs: make headings outline-minor-mode compatible
`outline-minor-mode' treats comments that begin with three or more
semicolons as headings. That makes it very convenient to navigate
code and to show/hide parts of a file.
Elips libraries typically have four top-level sections, e.g.:
;;; notmuch.el --- run notmuch within emacs...
;;; Commentary:...
;;; Code:...
;;; notmuch.el ends here
In this package many libraries lack a "Commentary:" section, which is
not optimal but okay for most libraries, except major entry points.
Depending on how one chooses to look at it, the "... ends here" line
is not really a heading that begins a section, because it should never
have a "section" body (after all it marks eof).
If the file is rather short, then I left "Code:" as the only section
that contains code. Otherwise I split the file into multiple sibling
sections. The "Code:" section continues to contain `require' and
`declare-function' forms and other such "front matter".
If and only if I have split the code into multiple sections anyway,
then I also added an additional section named just "_" before the
`provide' form and shortly before the "...end here" line. This
section could also be called "Back matter", but I feel it would be
distracting to be that explicit about it. (The IMO unnecessary but
unfortunately still obligatory "... ends here" line is already
distracting enough as far as I am concerned.)
Before this commit some libraries already uses section headings, some
of them consistently. When a library already had some headings, then
this commit often sticks to that style, even at the cost inconsistent
styling across all libraries.
A very limited number of variable and function definitions have to be
moved around because they would otherwise end up in sections they do
not belong into.
Sections, including but not limited to their heading, can and should
be further improved in the future.
2021-01-10 15:00:46 +01:00
|
|
|
;;; test-lib.el --- auxiliary stuff for Notmuch Emacs tests
|
2011-05-26 18:27:58 +02:00
|
|
|
;;
|
|
|
|
;; Copyright © Carl Worth
|
|
|
|
;; Copyright © David Edmondson
|
|
|
|
;;
|
|
|
|
;; This file is part of Notmuch test suit.
|
|
|
|
;;
|
|
|
|
;; Notmuch is free software: you can redistribute it and/or modify it
|
|
|
|
;; under the terms of the GNU General Public License as published by
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
;; (at your option) any later version.
|
|
|
|
;;
|
|
|
|
;; Notmuch is distributed in the hope that it will be useful, but
|
|
|
|
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
;; General Public License for more details.
|
|
|
|
;;
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2016-06-02 18:26:14 +02:00
|
|
|
;; along with Notmuch. If not, see <https://www.gnu.org/licenses/>.
|
2011-05-26 18:27:58 +02:00
|
|
|
;;
|
|
|
|
;; Authors: Dmitry Kurochkin <dmitry.kurochkin@gmail.com>
|
|
|
|
|
emacs: make headings outline-minor-mode compatible
`outline-minor-mode' treats comments that begin with three or more
semicolons as headings. That makes it very convenient to navigate
code and to show/hide parts of a file.
Elips libraries typically have four top-level sections, e.g.:
;;; notmuch.el --- run notmuch within emacs...
;;; Commentary:...
;;; Code:...
;;; notmuch.el ends here
In this package many libraries lack a "Commentary:" section, which is
not optimal but okay for most libraries, except major entry points.
Depending on how one chooses to look at it, the "... ends here" line
is not really a heading that begins a section, because it should never
have a "section" body (after all it marks eof).
If the file is rather short, then I left "Code:" as the only section
that contains code. Otherwise I split the file into multiple sibling
sections. The "Code:" section continues to contain `require' and
`declare-function' forms and other such "front matter".
If and only if I have split the code into multiple sections anyway,
then I also added an additional section named just "_" before the
`provide' form and shortly before the "...end here" line. This
section could also be called "Back matter", but I feel it would be
distracting to be that explicit about it. (The IMO unnecessary but
unfortunately still obligatory "... ends here" line is already
distracting enough as far as I am concerned.)
Before this commit some libraries already uses section headings, some
of them consistently. When a library already had some headings, then
this commit often sticks to that style, even at the cost inconsistent
styling across all libraries.
A very limited number of variable and function definitions have to be
moved around because they would otherwise end up in sections they do
not belong into.
Sections, including but not limited to their heading, can and should
be further improved in the future.
2021-01-10 15:00:46 +01:00
|
|
|
;;; Code:
|
|
|
|
|
2020-04-25 22:18:07 +02:00
|
|
|
(require 'cl-lib)
|
2012-01-24 17:14:06 +01:00
|
|
|
|
2020-07-27 17:25:01 +02:00
|
|
|
;; Ensure that the dynamic variables that are defined by this library
|
|
|
|
;; are defined by the time that we let-bind them. This is needed
|
|
|
|
;; because starting with Emacs 27 undeclared variables in evaluated
|
|
|
|
;; interactive code (such as our tests) use lexical scope.
|
|
|
|
(require 'smtpmail)
|
|
|
|
|
2011-06-28 06:56:17 +02:00
|
|
|
;; `read-file-name' by default uses `completing-read' function to read
|
|
|
|
;; user input. It does not respect `standard-input' variable which we
|
|
|
|
;; use in tests to provide user input. So replace it with a plain
|
|
|
|
;; `read' call.
|
|
|
|
(setq read-file-name-function (lambda (&rest _) (read)))
|
|
|
|
|
2011-06-28 06:45:04 +02:00
|
|
|
(defun notmuch-test-wait ()
|
|
|
|
"Wait for process completion."
|
|
|
|
(while (get-buffer-process (current-buffer))
|
2012-08-05 13:13:01 +02:00
|
|
|
(accept-process-output nil 0.1)))
|
2011-06-28 06:45:04 +02:00
|
|
|
|
2011-06-28 06:45:06 +02:00
|
|
|
(defun test-output (&optional filename)
|
|
|
|
"Save current buffer to file FILENAME. Default FILENAME is OUTPUT."
|
2014-05-09 02:20:07 +02:00
|
|
|
(notmuch-post-command)
|
2011-06-28 06:45:06 +02:00
|
|
|
(write-region (point-min) (point-max) (or filename "OUTPUT")))
|
|
|
|
|
|
|
|
(defun test-visible-output (&optional filename)
|
|
|
|
"Save visible text in current buffer to file FILENAME. Default
|
|
|
|
FILENAME is OUTPUT."
|
2014-05-09 02:20:07 +02:00
|
|
|
(notmuch-post-command)
|
2014-04-21 20:37:39 +02:00
|
|
|
(let ((text (visible-buffer-string))
|
|
|
|
;; Tests expect output in UTF-8 encoding
|
|
|
|
(coding-system-for-write 'utf-8))
|
2011-06-28 06:45:06 +02:00
|
|
|
(with-temp-file (or filename "OUTPUT") (insert text))))
|
|
|
|
|
2011-05-26 18:27:58 +02:00
|
|
|
(defun visible-buffer-string ()
|
2012-01-26 08:19:37 +01:00
|
|
|
"Same as `buffer-string', but excludes invisible text and
|
|
|
|
removes any text properties."
|
2011-05-26 18:27:58 +02:00
|
|
|
(visible-buffer-substring (point-min) (point-max)))
|
|
|
|
|
|
|
|
(defun visible-buffer-substring (start end)
|
2012-01-26 08:19:37 +01:00
|
|
|
"Same as `buffer-substring-no-properties', but excludes
|
|
|
|
invisible text."
|
2011-05-26 18:27:58 +02:00
|
|
|
(let (str)
|
|
|
|
(while (< start end)
|
|
|
|
(let ((next-pos (next-char-property-change start end)))
|
2020-08-08 13:49:42 +02:00
|
|
|
(unless (invisible-p start)
|
2012-01-26 08:19:37 +01:00
|
|
|
(setq str (concat str (buffer-substring-no-properties
|
|
|
|
start next-pos))))
|
2011-05-26 18:27:58 +02:00
|
|
|
(setq start next-pos)))
|
|
|
|
str))
|
2011-06-28 06:56:17 +02:00
|
|
|
|
2014-01-11 18:25:39 +01:00
|
|
|
;; process-attributes is not defined everywhere, so define an
|
|
|
|
;; alternate way to test if a process still exists.
|
|
|
|
|
|
|
|
(defun test-process-running (pid)
|
|
|
|
(= 0
|
|
|
|
(signal-process pid 0)))
|
|
|
|
|
2013-01-30 00:06:37 +01:00
|
|
|
(defun orphan-watchdog-check (pid)
|
2011-06-28 06:56:17 +02:00
|
|
|
"Periodically check that the process with id PID is still
|
|
|
|
running, quit if it terminated."
|
2020-08-08 13:49:42 +02:00
|
|
|
(unless (test-process-running pid)
|
|
|
|
(kill-emacs)))
|
2013-01-30 00:06:37 +01:00
|
|
|
|
|
|
|
(defun orphan-watchdog (pid)
|
|
|
|
"Initiate orphan watchdog check."
|
2014-01-11 18:25:39 +01:00
|
|
|
(run-at-time 60 60 'orphan-watchdog-check pid))
|
2011-12-18 01:21:18 +01:00
|
|
|
|
2020-07-27 17:25:01 +02:00
|
|
|
(defvar notmuch-hello-mode-hook-counter -100
|
|
|
|
"Tests that care about this counter must let-bind it to 0.")
|
2020-07-27 17:25:02 +02:00
|
|
|
(add-hook 'notmuch-hello-mode-hook
|
|
|
|
(lambda () (cl-incf notmuch-hello-mode-hook-counter)))
|
2020-07-27 17:25:01 +02:00
|
|
|
|
|
|
|
(defvar notmuch-hello-refresh-hook-counter -100
|
|
|
|
"Tests that care about this counter must let-bind it to 0.")
|
2020-07-27 17:25:02 +02:00
|
|
|
(add-hook 'notmuch-hello-refresh-hook
|
|
|
|
(lambda () (cl-incf notmuch-hello-refresh-hook-counter)))
|
2020-07-27 17:25:01 +02:00
|
|
|
|
2021-05-08 14:11:11 +02:00
|
|
|
(defvar notmuch-test-tag-hook-output nil)
|
|
|
|
(defun notmuch-test-tag-hook () (push (cons query tag-changes) notmuch-test-tag-hook-output))
|
|
|
|
|
2012-11-15 20:49:52 +01:00
|
|
|
(defun notmuch-test-mark-links ()
|
|
|
|
"Enclose links in the current buffer with << and >>."
|
|
|
|
;; Links are often created by jit-lock functions
|
|
|
|
(jit-lock-fontify-now)
|
|
|
|
(save-excursion
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
(goto-char (point-min))
|
|
|
|
(let ((button))
|
|
|
|
(while (setq button (next-button (point)))
|
|
|
|
(goto-char (button-start button))
|
|
|
|
(insert "<<")
|
|
|
|
(goto-char (button-end button))
|
|
|
|
(insert ">>"))))))
|
|
|
|
|
2012-01-24 17:14:05 +01:00
|
|
|
(defmacro notmuch-test-run (&rest body)
|
|
|
|
"Evaluate a BODY of test expressions and output the result."
|
|
|
|
`(with-temp-buffer
|
2012-01-26 08:19:38 +01:00
|
|
|
(let ((buffer (current-buffer))
|
|
|
|
(result (progn ,@body)))
|
|
|
|
(switch-to-buffer buffer)
|
2012-01-24 17:14:05 +01:00
|
|
|
(insert (if (stringp result)
|
|
|
|
result
|
|
|
|
(prin1-to-string result)))
|
|
|
|
(test-output))))
|
2012-01-24 17:14:06 +01:00
|
|
|
|
|
|
|
(defun notmuch-test-report-unexpected (output expected)
|
|
|
|
"Report that the OUTPUT does not match the EXPECTED result."
|
|
|
|
(concat "Expect:\t" (prin1-to-string expected) "\n"
|
|
|
|
"Output:\t" (prin1-to-string output) "\n"))
|
|
|
|
|
|
|
|
(defun notmuch-test-expect-equal (output expected)
|
2020-08-08 13:49:55 +02:00
|
|
|
"Compare OUTPUT with EXPECTED. Report any discrepancies."
|
2020-08-08 13:49:53 +02:00
|
|
|
(cond
|
|
|
|
((equal output expected)
|
|
|
|
t)
|
|
|
|
((and (listp output)
|
|
|
|
(listp expected))
|
|
|
|
;; Reporting the difference between two lists is done by
|
|
|
|
;; reporting differing elements of OUTPUT and EXPECTED
|
|
|
|
;; pairwise. This is expected to make analysis of failures
|
|
|
|
;; simpler.
|
|
|
|
(apply #'concat (cl-loop for o in output
|
|
|
|
for e in expected
|
|
|
|
if (not (equal o e))
|
|
|
|
collect (notmuch-test-report-unexpected o e))))
|
|
|
|
(t
|
|
|
|
(notmuch-test-report-unexpected output expected))))
|
emacs: show: mark tags changed since buffer loaded
This allows (and requires) the original-tags to be passed along with
the current-tags to be passed to notmuch-tag-format-tags. This allows
the tag formatting to show added and deleted tags.By default a removed
tag is displayed with strike-through in red (if strike-through is not
available, eg on a terminal, inverse video is used instead) and an
added tag is displayed underlined in green.
If the caller does not wish to use the new feature it can pass
current-tags for both arguments and, at this point, we do exactly that
in the three callers of this function.
Note, we cannot tidily allow original-tags to be optional because we would
need to distinguish nil meaning "we are not specifying original-tags"
from nil meaning there were no original-tags (an empty list).
We use this in subsequent patches to make it clear when a message was
unread when you first loaded a show buffer (previously the unread tag
could be removed before a user realised that it had been unread).
The code adds into the existing tag formatting code. The user can
specify exactly how a tag should be displayed normally, when deleted,
or when added.
Since the formatting code matches regexps a user can match all deleted
tags with a ".*" in notmuch-tag-deleted-formats. For example setting
notmuch-tag-deleted-formats to '((".*" nil)) tells notmuch not to show
deleted tags at all.
All the variables are customizable; however, more complicated cases
like changing the face depending on the type of display will require
custom lisp.
Currently this overrides notmuch-tag-deleted-formats for the tests
setting it to '((".*" nil)) so that they get removed from the display
and, thus, all tests still pass.
2014-03-22 12:51:09 +01:00
|
|
|
|
2014-05-09 02:20:07 +02:00
|
|
|
(defun notmuch-post-command ()
|
|
|
|
(run-hooks 'post-command-hook))
|
|
|
|
|
|
|
|
(defmacro notmuch-test-progn (&rest body)
|
|
|
|
(cons 'progn
|
|
|
|
(mapcar
|
|
|
|
(lambda (x) `(prog1 ,x (notmuch-post-command)))
|
|
|
|
body)))
|
|
|
|
|
2021-08-30 21:49:06 +02:00
|
|
|
;; For testing functions in
|
|
|
|
;; notmuch-{search,tree,unsorted}-result-format
|
|
|
|
(defun notmuch-test-result-flags (format-string result)
|
|
|
|
(let ((tags-to-letters (quote (("attachment" . "&")
|
|
|
|
("signed" . "=")
|
|
|
|
("unread" . "u")
|
|
|
|
("inbox" . "i"))))
|
|
|
|
(tags (plist-get result :tags)))
|
|
|
|
(format format-string
|
|
|
|
(mapconcat (lambda (t2l)
|
|
|
|
(if (member (car t2l) tags)
|
|
|
|
(cdr t2l)
|
|
|
|
" "))
|
|
|
|
tags-to-letters ""))))
|
|
|
|
|
2021-08-29 21:23:27 +02:00
|
|
|
;; Log any signalled error (and other messages) to MESSAGES
|
|
|
|
;; Log "COMPLETE" if forms complete without error.
|
|
|
|
(defmacro test-log-error (&rest body)
|
|
|
|
`(progn
|
|
|
|
(with-current-buffer "*Messages*"
|
|
|
|
(let ((inhibit-read-only t)) (erase-buffer)))
|
|
|
|
(condition-case err
|
|
|
|
(progn ,@body
|
|
|
|
(message "COMPLETE"))
|
|
|
|
(t (message "%s" err)))
|
|
|
|
(with-current-buffer "*Messages*" (test-output "MESSAGES"))))
|
|
|
|
|
2022-02-12 21:27:35 +01:00
|
|
|
(defmacro test-time (&rest body)
|
|
|
|
`(let ((results (mapcar (lambda (x) (/ x 5.0)) (benchmark-run 5 ,@body))))
|
|
|
|
(message "\t\t%0.2f\t%0.2f\t%0.2f" (nth 0 results) (nth 1 results) (nth 2 results))
|
|
|
|
(with-current-buffer "*Messages*" (test-output "MESSAGES"))))
|
|
|
|
|
emacs: show: mark tags changed since buffer loaded
This allows (and requires) the original-tags to be passed along with
the current-tags to be passed to notmuch-tag-format-tags. This allows
the tag formatting to show added and deleted tags.By default a removed
tag is displayed with strike-through in red (if strike-through is not
available, eg on a terminal, inverse video is used instead) and an
added tag is displayed underlined in green.
If the caller does not wish to use the new feature it can pass
current-tags for both arguments and, at this point, we do exactly that
in the three callers of this function.
Note, we cannot tidily allow original-tags to be optional because we would
need to distinguish nil meaning "we are not specifying original-tags"
from nil meaning there were no original-tags (an empty list).
We use this in subsequent patches to make it clear when a message was
unread when you first loaded a show buffer (previously the unread tag
could be removed before a user realised that it had been unread).
The code adds into the existing tag formatting code. The user can
specify exactly how a tag should be displayed normally, when deleted,
or when added.
Since the formatting code matches regexps a user can match all deleted
tags with a ".*" in notmuch-tag-deleted-formats. For example setting
notmuch-tag-deleted-formats to '((".*" nil)) tells notmuch not to show
deleted tags at all.
All the variables are customizable; however, more complicated cases
like changing the face depending on the type of display will require
custom lisp.
Currently this overrides notmuch-tag-deleted-formats for the tests
setting it to '((".*" nil)) so that they get removed from the display
and, thus, all tests still pass.
2014-03-22 12:51:09 +01:00
|
|
|
;; For historical reasons, we hide deleted tags by default in the test
|
|
|
|
;; suite
|
|
|
|
(setq notmuch-tag-deleted-formats
|
|
|
|
'((".*" nil)))
|
2014-09-20 07:41:35 +02:00
|
|
|
|
2016-09-04 00:59:43 +02:00
|
|
|
;; Also for historical reasons, we set the fcc handler to file not
|
|
|
|
;; insert.
|
|
|
|
|
|
|
|
(setq notmuch-maildir-use-notmuch-insert nil)
|
|
|
|
|
2014-09-20 07:41:35 +02:00
|
|
|
;; force a common html renderer, to avoid test variations between
|
|
|
|
;; environments
|
|
|
|
|
|
|
|
(setq mm-text-html-renderer 'html2text)
|
2023-08-20 19:32:02 +02:00
|
|
|
|
|
|
|
;; Set our own default for message-hidden-headers, to avoid tests
|
|
|
|
;; breaking when the Emacs default changes.
|
|
|
|
(setq message-hidden-headers
|
|
|
|
'("^References:" "^Face:" "^X-Face:" "^X-Draft-From:"))
|