branch: elpa/logview
commit 49cca08b84a6ef26f6ce701086eaa2b6483dce8f
Author: Paul Pogonyshev <pogonys...@gmail.com>
Commit: Paul Pogonyshev <pogonys...@gmail.com>

    Handle errors in mode initialization in such a way as to never leave it in 
half-initialized state (related to issue #55).
---
 logview.el      | 13 +++++++++++++
 test/logview.el | 52 +++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 56 insertions(+), 9 deletions(-)

diff --git a/logview.el b/logview.el
index 61ffe64430..041b2a17ff 100644
--- a/logview.el
+++ b/logview.el
@@ -1212,6 +1212,19 @@ successfully.")
 ;;;###autoload
 (define-derived-mode logview-mode nil "Logview"
   "Major mode for viewing and filtering various log files."
+  (let (successful)
+    (unwind-protect
+        (progn (logview--set-up)
+               (setf successful t))
+      (unless successful
+        ;; Don't leave the mode half-initialized if there is any unhandled 
error.  This is
+        ;; not how Emacs normally works, but standard way is too confusing to 
users and
+        ;; behavior depends on where exactly an error happened.  Also, as 
function
+        ;; `normal-mode' effectively eats the error (at least its backtrace), 
debugging it
+        ;; is nearly impossible anyway.
+        (fundamental-mode)))))
+
+(defun logview--set-up ()
   ;; {LOCKED-NARROWING}
   ;; Logview is incompatible with locked narrowing of Emacs 29.  Later 
snapshots sort of
   ;; allow us to unlock this shit sometimes, but not the earlier, there we can 
only set
diff --git a/test/logview.el b/test/logview.el
index aca79a6b65..b4eb08dadf 100644
--- a/test/logview.el
+++ b/test/logview.el
@@ -22,11 +22,32 @@
 (require 'subr-x)
 
 
+(define-error 'logview-test-expected-error "Must be caught")
+
 (defvar logview--test-directory (file-name-directory (or load-file-name 
(buffer-file-name))))
 
 (defvar inhibit-message)
 
 
+;; Copied from Eldev source code, see documentation there.
+(defmacro logview--advised (spec &rest body)
+  (declare (indent 1) (debug (sexp body)))
+  (let ((symbol   (nth 0 spec))
+        (where    (nth 1 spec))
+        (function (nth 2 spec))
+        (props    (nthcdr 3 spec))
+        (fn       (make-symbol "$fn")))
+    `(let ((,fn ,function))
+       (when ,fn
+         (if (advice-member-p ,fn ,symbol)
+             (setf ,fn nil)
+           (advice-add ,symbol ,where ,fn ,@props)))
+       (unwind-protect
+           ,(macroexp-progn body)
+         (when ,fn
+           (advice-remove ,symbol ,fn))))))
+
+
 (defmacro logview--test-with-restriction (start end locking-label &rest body)
   (declare (indent 3))
   (if (fboundp 'with-restriction)
@@ -56,8 +77,22 @@
           (should (string= (buffer-string) "foo bar baz")))))))
 
 
-(defun logview--test-display-warning-advice (&rest arguments)
-  (error "Warning elevated to an error: %S" arguments))
+(ert-deftest logview-mode ()
+  (with-temp-buffer
+    (insert "2020-01-01 00:00:00 [thread 1] INFO hello - world\n")
+    (logview-mode)
+    (should (eq major-mode 'logview-mode))))
+
+
+(ert-deftest logview-mode-unsuccessful-setup ()
+  (condition-case nil
+      (logview--advised (#'logview--set-up :override (lambda () (signal 
'logview-test-expected-error nil)))
+        (with-temp-buffer
+          (logview-mode)
+          ;; Errors during mode setup must not leave the mode half-initialized.
+          (should (eq major-mode 'fundamental-mode))))
+    (logview-test-expected-error)))
+
 
 (defmacro logview--test-with-file (filename &rest body)
   "Activate Logview in a temporary buffer with contents of the file.
@@ -86,13 +121,12 @@ buffer if the test needs that."
     `(let (,@erase-customizations
            ,@extra-customizations
            (inhibit-message t))
-       (advice-add 'display-warning :override 
#'logview--test-display-warning-advice)
-       (unwind-protect
-           (with-temp-buffer
-             (insert-file-contents (expand-file-name ,filename 
logview--test-directory))
-             (,(or buffer-mode 'logview-mode))
-             ,@body)
-         (advice-remove 'display-warning 
#'logview--test-display-warning-advice)))))
+       (logview--advised ('display-warning :override (lambda (&rest arguments)
+                                                       (error "Warning 
elevated to an error: %S" arguments)))
+         (with-temp-buffer
+           (insert-file-contents (expand-file-name ,filename 
logview--test-directory))
+           (,(or buffer-mode 'logview-mode))
+           ,@body)))))
 
 
 (defun logview--test-user-visible-buffer-string ()

Reply via email to