aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/emacs-lisp/debug.el71
-rw-r--r--lisp/emacs-lisp/ert.el85
-rw-r--r--test/lisp/emacs-lisp/ert-tests.el8
3 files changed, 38 insertions, 126 deletions
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 62e413bd8d0..7db0f91b746 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -370,77 +370,6 @@ That buffer should be current already."
370 ;; Place point on "stack frame 0" (bug#15101). 370 ;; Place point on "stack frame 0" (bug#15101).
371 (goto-char pos))) 371 (goto-char pos)))
372 372
373
374(defun debugger-make-xrefs (&optional buffer)
375 "Attach cross-references to function names in the `*Backtrace*' buffer."
376 (interactive "b")
377 (with-current-buffer (or buffer (current-buffer))
378 (save-excursion
379 (setq buffer (current-buffer))
380 (let ((inhibit-read-only t)
381 (old-end (point-min)) (new-end (point-min)))
382 ;; If we saved an old backtrace, find the common part
383 ;; between the new and the old.
384 ;; Compare line by line, starting from the end,
385 ;; because that's the part that is likely to be unchanged.
386 (if debugger-previous-backtrace
387 (let (old-start new-start (all-match t))
388 (goto-char (point-max))
389 (with-temp-buffer
390 (insert debugger-previous-backtrace)
391 (while (and all-match (not (bobp)))
392 (setq old-end (point))
393 (forward-line -1)
394 (setq old-start (point))
395 (with-current-buffer buffer
396 (setq new-end (point))
397 (forward-line -1)
398 (setq new-start (point)))
399 (if (not (zerop
400 (let ((case-fold-search nil))
401 (compare-buffer-substrings
402 (current-buffer) old-start old-end
403 buffer new-start new-end))))
404 (setq all-match nil))))
405 ;; Now new-end is the position of the start of the
406 ;; unchanged part in the current buffer, and old-end is
407 ;; the position of that same text in the saved old
408 ;; backtrace. But we must subtract (point-min) since strings are
409 ;; indexed in origin 0.
410
411 ;; Replace the unchanged part of the backtrace
412 ;; with the text from debugger-previous-backtrace,
413 ;; since that already has the proper xrefs.
414 ;; With this optimization, we only need to scan
415 ;; the changed part of the backtrace.
416 (delete-region new-end (point-max))
417 (goto-char (point-max))
418 (insert (substring debugger-previous-backtrace
419 (- old-end (point-min))))
420 ;; Make the unchanged part of the backtrace inaccessible
421 ;; so it won't be scanned.
422 (narrow-to-region (point-min) new-end)))
423
424 ;; Scan the new part of the backtrace, inserting xrefs.
425 (goto-char (point-min))
426 (while (progn
427 (goto-char (+ (point) 2))
428 (skip-syntax-forward "^w_")
429 (not (eobp)))
430 (let* ((beg (point))
431 (end (progn (skip-syntax-forward "w_") (point)))
432 (sym (intern-soft (buffer-substring-no-properties
433 beg end)))
434 (file (and sym (symbol-file sym 'defun))))
435 (when file
436 (goto-char beg)
437 ;; help-xref-button needs to operate on something matched
438 ;; by a regexp, so set that up for it.
439 (re-search-forward "\\(\\sw\\|\\s_\\)+")
440 (help-xref-button 0 'help-function-def sym file)))
441 (forward-line 1))
442 (widen))
443 (setq debugger-previous-backtrace (buffer-string)))))
444 373
445(defun debugger-step-through () 374(defun debugger-step-through ()
446 "Proceed, stepping through subexpressions of this expression. 375 "Proceed, stepping through subexpressions of this expression.
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index 2c49a634e35..7edc40188e1 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -670,48 +670,12 @@ and is displayed in front of the value of MESSAGE-FORM."
670(cl-defstruct (ert-test-aborted-with-non-local-exit 670(cl-defstruct (ert-test-aborted-with-non-local-exit
671 (:include ert-test-result))) 671 (:include ert-test-result)))
672 672
673 673(defun ert--print-backtrace (backtrace do-xrefs)
674(defun ert--record-backtrace ()
675 "Record the current backtrace (as a list) and return it."
676 ;; Since the backtrace is stored in the result object, result
677 ;; objects must only be printed with appropriate limits
678 ;; (`print-level' and `print-length') in place. For interactive
679 ;; use, the cost of ensuring this possibly outweighs the advantage
680 ;; of storing the backtrace for
681 ;; `ert-results-pop-to-backtrace-for-test-at-point' given that we
682 ;; already have `ert-results-rerun-test-debugging-errors-at-point'.
683 ;; For batch use, however, printing the backtrace may be useful.
684 (cl-loop
685 ;; 6 is the number of frames our own debugger adds (when
686 ;; compiled; more when interpreted). FIXME: Need to describe a
687 ;; procedure for determining this constant.
688 for i from 6
689 for frame = (backtrace-frame i)
690 while frame
691 collect frame))
692
693(defun ert--print-backtrace (backtrace)
694 "Format the backtrace BACKTRACE to the current buffer." 674 "Format the backtrace BACKTRACE to the current buffer."
695 ;; This is essentially a reimplementation of Fbacktrace
696 ;; (src/eval.c), but for a saved backtrace, not the current one.
697 (let ((print-escape-newlines t) 675 (let ((print-escape-newlines t)
698 (print-level 8) 676 (print-level 8)
699 (print-length 50)) 677 (print-length 50))
700 (dolist (frame backtrace) 678 (debugger-insert-backtrace backtrace do-xrefs)))
701 (pcase-exhaustive frame
702 (`(nil ,special-operator . ,arg-forms)
703 ;; Special operator.
704 (insert
705 (format " %S\n" (cons special-operator arg-forms))))
706 (`(t ,fn . ,args)
707 ;; Function call.
708 (insert (format " %S(" fn))
709 (cl-loop for firstp = t then nil
710 for arg in args do
711 (unless firstp
712 (insert " "))
713 (insert (format "%S" arg)))
714 (insert ")\n"))))))
715 679
716;; A container for the state of the execution of a single test and 680;; A container for the state of the execution of a single test and
717;; environment data needed during its execution. 681;; environment data needed during its execution.
@@ -750,7 +714,19 @@ run. ARGS are the arguments to `debugger'."
750 ((quit) 'quit) 714 ((quit) 'quit)
751 ((ert-test-skipped) 'skipped) 715 ((ert-test-skipped) 'skipped)
752 (otherwise 'failed))) 716 (otherwise 'failed)))
753 (backtrace (ert--record-backtrace)) 717 ;; We store the backtrace in the result object for
718 ;; `ert-results-pop-to-backtrace-for-test-at-point'.
719 ;; This means we have to limit `print-level' and
720 ;; `print-length' when printing result objects. That
721 ;; might not be worth while when we can also use
722 ;; `ert-results-rerun-test-debugging-errors-at-point',
723 ;; (i.e., when running interactively) but having the
724 ;; backtrace ready for printing is important for batch
725 ;; use.
726 ;;
727 ;; Grab the frames starting from `signal', frames below
728 ;; that are all from the debugger.
729 (backtrace (backtrace-frames 'signal))
754 (infos (reverse ert--infos))) 730 (infos (reverse ert--infos)))
755 (setf (ert--test-execution-info-result info) 731 (setf (ert--test-execution-info-result info)
756 (cl-ecase type 732 (cl-ecase type
@@ -1409,8 +1385,9 @@ Returns the stats object."
1409 (ert-test-result-with-condition 1385 (ert-test-result-with-condition
1410 (message "Test %S backtrace:" (ert-test-name test)) 1386 (message "Test %S backtrace:" (ert-test-name test))
1411 (with-temp-buffer 1387 (with-temp-buffer
1412 (ert--print-backtrace (ert-test-result-with-condition-backtrace 1388 (ert--print-backtrace
1413 result)) 1389 (ert-test-result-with-condition-backtrace result)
1390 nil)
1414 (goto-char (point-min)) 1391 (goto-char (point-min))
1415 (while (not (eobp)) 1392 (while (not (eobp))
1416 (let ((start (point)) 1393 (let ((start (point))
@@ -1828,12 +1805,23 @@ EWOC and STATS are arguments for `ert--results-update-stats-display'."
1828 1805
1829BEGIN and END specify a region in the current buffer." 1806BEGIN and END specify a region in the current buffer."
1830 (save-excursion 1807 (save-excursion
1831 (save-restriction 1808 (goto-char begin)
1832 (narrow-to-region begin end) 1809 (while (progn
1833 ;; Inhibit optimization in `debugger-make-xrefs' that would 1810 (goto-char (+ (point) 2))
1834 ;; sometimes insert unrelated backtrace info into our buffer. 1811 (skip-syntax-forward "^w_")
1835 (let ((debugger-previous-backtrace nil)) 1812 (< (point) end))
1836 (debugger-make-xrefs))))) 1813 (let* ((beg (point))
1814 (end (progn (skip-syntax-forward "w_") (point)))
1815 (sym (intern-soft (buffer-substring-no-properties
1816 beg end)))
1817 (file (and sym (symbol-file sym 'defun))))
1818 (when file
1819 (goto-char beg)
1820 ;; help-xref-button needs to operate on something matched
1821 ;; by a regexp, so set that up for it.
1822 (re-search-forward "\\(\\sw\\|\\s_\\)+")
1823 (help-xref-button 0 'help-function-def sym file)))
1824 (forward-line 1))))
1837 1825
1838(defun ert--string-first-line (s) 1826(defun ert--string-first-line (s)
1839 "Return the first line of S, or S if it contains no newlines. 1827 "Return the first line of S, or S if it contains no newlines.
@@ -2420,8 +2408,7 @@ To be used in the ERT results buffer."
2420 ;; Use unibyte because `debugger-setup-buffer' also does so. 2408 ;; Use unibyte because `debugger-setup-buffer' also does so.
2421 (set-buffer-multibyte nil) 2409 (set-buffer-multibyte nil)
2422 (setq truncate-lines t) 2410 (setq truncate-lines t)
2423 (ert--print-backtrace backtrace) 2411 (ert--print-backtrace backtrace t)
2424 (debugger-make-xrefs)
2425 (goto-char (point-min)) 2412 (goto-char (point-min))
2426 (insert (substitute-command-keys "Backtrace for test `")) 2413 (insert (substitute-command-keys "Backtrace for test `"))
2427 (ert-insert-test-name-button (ert-test-name test)) 2414 (ert-insert-test-name-button (ert-test-name test))
diff --git a/test/lisp/emacs-lisp/ert-tests.el b/test/lisp/emacs-lisp/ert-tests.el
index fc5790c3659..317838b250f 100644
--- a/test/lisp/emacs-lisp/ert-tests.el
+++ b/test/lisp/emacs-lisp/ert-tests.el
@@ -367,12 +367,8 @@ This macro is used to test if macroexpansion in `should' works."
367 (test (make-ert-test :body test-body)) 367 (test (make-ert-test :body test-body))
368 (result (ert-run-test test))) 368 (result (ert-run-test test)))
369 (should (ert-test-failed-p result)) 369 (should (ert-test-failed-p result))
370 (with-temp-buffer 370 (should (eq (nth 1 (car (ert-test-failed-backtrace result)))
371 (ert--print-backtrace (ert-test-failed-backtrace result)) 371 'signal))))
372 (goto-char (point-min))
373 (end-of-line)
374 (let ((first-line (buffer-substring-no-properties (point-min) (point))))
375 (should (equal first-line (format " %S()" test-body)))))))
376 372
377(ert-deftest ert-test-messages () 373(ert-deftest ert-test-messages ()
378 :tags '(:causes-redisplay) 374 :tags '(:causes-redisplay)