aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--test/lisp/emacs-lisp/backtrace-tests.el399
1 files changed, 352 insertions, 47 deletions
diff --git a/test/lisp/emacs-lisp/backtrace-tests.el b/test/lisp/emacs-lisp/backtrace-tests.el
index 75da468494b..ba2d33a9d5c 100644
--- a/test/lisp/emacs-lisp/backtrace-tests.el
+++ b/test/lisp/emacs-lisp/backtrace-tests.el
@@ -1,4 +1,4 @@
1;;; backtrace-tests.el --- Tests for emacs-lisp/backtrace.el -*- lexical-binding: t; -*- 1;;; backtrace-tests.el --- Tests for backtraces -*- lexical-binding: t; -*-
2 2
3;; Copyright (C) 2018 Free Software Foundation, Inc. 3;; Copyright (C) 2018 Free Software Foundation, Inc.
4 4
@@ -23,67 +23,372 @@
23 23
24(require 'backtrace) 24(require 'backtrace)
25(require 'ert) 25(require 'ert)
26(require 'ert-x)
26(require 'seq) 27(require 'seq)
27 28
28;; Create a backtrace frames list with several frames. 29;; Delay evaluation of the backtrace-creating functions until
29;; TODO load this from an el file in backtrace-resources/ so the tests 30;; load so that the backtraces are the same whether this file
30;; can be byte-compiled. 31;; is compiled or not.
31(defvar backtrace-tests--frames nil)
32 32
33(defun backtrace-tests--func1 (arg1 arg2) 33(eval-and-compile
34 (setq backtrace-tests--frames (backtrace-get-frames nil)) 34 (defconst backtrace-tests--uncompiled-functions
35 (list arg1 arg2)) 35 '(progn
36 (defun backtrace-tests--make-backtrace (arg)
37 (backtrace-tests--setup-buffer))
36 38
37(defun backtrace-tests--func2 (arg) 39 (defun backtrace-tests--setup-buffer ()
38 (list arg)) 40 "Set up the current buffer in backtrace mode."
41 (backtrace-mode)
42 (setq backtrace-frames (backtrace-get-frames))
43 (let ((this-index))
44 ;; Discard all past `backtrace-tests-make-backtrace'.
45 (dotimes (index (length backtrace-frames))
46 (when (eq (backtrace-frame-fun (nth index backtrace-frames))
47 'backtrace-tests--make-backtrace)
48 (setq this-index index)))
49 (setq backtrace-frames (seq-subseq backtrace-frames 0 (1+ this-index))))
50 (backtrace-print))))
39 51
40(defun backtrace-tests--func3 (arg) 52 (eval backtrace-tests--uncompiled-functions))
41 (let ((foo (list 'a arg 'b)))
42 (list foo (backtrace-tests--func2 arg) (backtrace-tests--func1 arg 0))))
43 53
44(defun backtrace-tests--create-backtrace-frames () 54(defun backtrace-tests--backtrace-lines ()
45 (backtrace-tests--func3 "string") 55 (if debugger-stack-frame-as-list
46 ;; Discard frames before this one. 56 '(" (backtrace-get-frames)\n"
47 (let (this-index) 57 " (setq backtrace-frames (backtrace-get-frames))\n"
48 (dotimes (index (length backtrace-tests--frames)) 58 " (backtrace-tests--setup-buffer)\n"
49 (when (eq (backtrace-frame-fun (nth index backtrace-tests--frames)) 59 " (backtrace-tests--make-backtrace %s)\n")
50 'backtrace-tests--create-backtrace-frames) 60 '(" backtrace-get-frames()\n"
51 (setq this-index index))) 61 " (setq backtrace-frames (backtrace-get-frames))\n"
52 (setq backtrace-tests--frames (seq-subseq backtrace-tests--frames 62 " backtrace-tests--setup-buffer()\n"
53 0 (1+ this-index))))) 63 " backtrace-tests--make-backtrace(%s)\n")))
54 64
55(backtrace-tests--create-backtrace-frames) 65(defconst backtrace-tests--line-count (length (backtrace-tests--backtrace-lines)))
66
67(defun backtrace-tests--backtrace-lines-with-locals ()
68 (let ((lines (backtrace-tests--backtrace-lines))
69 (locals '(" [no locals]\n"
70 " [no locals]\n"
71 " [no locals]\n"
72 " arg = %s\n")))
73 (apply #'append (cl-mapcar #'list lines locals))))
74
75(defun backtrace-tests--result (value)
76 (format (apply #'concat (backtrace-tests--backtrace-lines))
77 (cl-prin1-to-string value)))
78
79(defun backtrace-tests--result-with-locals (value)
80 (let ((str (cl-prin1-to-string value)))
81 (format (apply #'concat (backtrace-tests--backtrace-lines-with-locals))
82 str str)))
56 83
57;; TODO check that debugger-batch-max-lines still works 84;; TODO check that debugger-batch-max-lines still works
58 85
86(defconst backtrace-tests--header "Test header\n")
59(defun backtrace-tests--insert-header () 87(defun backtrace-tests--insert-header ()
60 (insert "Test header\n")) 88 (insert backtrace-tests--header))
61
62(defmacro backtrace-tests--with-buffer (&rest body)
63 `(with-temp-buffer
64 (backtrace-mode)
65 (setq backtrace-frames backtrace-tests--frames)
66 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
67 (backtrace-print)
68 ,@body))
69 89
70;;; Tests 90;;; Tests
91
92(ert-deftest backtrace-tests--variables ()
93 "Backtrace buffers can show and hide local variables."
94 (ert-with-test-buffer (:name "variables")
95 (let ((results (concat backtrace-tests--header
96 (backtrace-tests--result 'value)))
97 (last-frame (format (nth (1- backtrace-tests--line-count)
98 (backtrace-tests--backtrace-lines)) 'value))
99 (last-frame-with-locals
100 (format (apply #'concat (nthcdr (* 2 (1- backtrace-tests--line-count))
101 (backtrace-tests--backtrace-lines-with-locals)))
102 'value 'value)))
103 (backtrace-tests--make-backtrace 'value)
104 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
105 (backtrace-print)
106 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
107 results))
108 ;; Go to the last frame.
109 (goto-char (point-max))
110 (forward-line -1)
111 ;; Turn on locals for that frame.
112 (backtrace-toggle-locals)
113 (should (string= (backtrace-tests--get-substring (point) (point-max))
114 last-frame-with-locals))
115 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
116 (concat results
117 (format (car (last (backtrace-tests--backtrace-lines-with-locals)))
118 'value))))
119 ;; Turn off locals for that frame.
120 (backtrace-toggle-locals)
121 (should (string= (backtrace-tests--get-substring (point) (point-max))
122 last-frame))
123 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
124 results))
125 ;; Turn all locals on.
126 (backtrace-toggle-locals '(4))
127 (should (string= (backtrace-tests--get-substring (point) (point-max))
128 last-frame-with-locals))
129 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
130 (concat backtrace-tests--header
131 (backtrace-tests--result-with-locals 'value))))
132 ;; Turn all locals off.
133 (backtrace-toggle-locals '(4))
134 (should (string= (backtrace-tests--get-substring
135 (point) (+ (point) (length last-frame)))
136 last-frame))
137 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
138 results)))))
139
140(ert-deftest backtrace-tests--backward-frame ()
141 "`backtrace-backward-frame' moves backward to the start of a frame."
142 (ert-with-test-buffer (:name "backward")
143 (let ((results (concat backtrace-tests--header
144 (backtrace-tests--result nil))))
145 (backtrace-tests--make-backtrace nil)
146 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
147 (backtrace-print)
148 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
149 results))
150
151 ;; Try to move backward from header.
152 (goto-char (+ (point-min) (/ (length backtrace-tests--header) 2)))
153 (let ((pos (point)))
154 (should-error (backtrace-backward-frame))
155 (should (= pos (point))))
156
157 ;; Try to move backward from start of first line.
158 (forward-line)
159 (let ((pos (point)))
160 (should-error (backtrace-backward-frame))
161 (should (= pos (point))))
162
163 ;; Move backward from middle of line.
164 (let ((start (point)))
165 (forward-char (/ (length (nth 0 (backtrace-tests--backtrace-lines))) 2))
166 (backtrace-backward-frame)
167 (should (= start (point))))
168
169 ;; Move backward from end of buffer.
170 (goto-char (point-max))
171 (backtrace-backward-frame)
172 (let* ((last (format (car (last (backtrace-tests--backtrace-lines))) nil))
173 (len (length last)))
174 (should (string= (buffer-substring-no-properties (point) (+ (point) len))
175 last)))
176
177 ;; Move backward from start of line.
178 (backtrace-backward-frame)
179 (let* ((line (car (last (backtrace-tests--backtrace-lines) 2)))
180 (len (length line)))
181 (should (string= (buffer-substring-no-properties (point) (+ (point) len))
182 line))))))
183
184(ert-deftest backtrace-tests--forward-frame ()
185 "`backtrace-forward-frame' moves forward to the start of a frame."
186 (ert-with-test-buffer (:name "forward")
187 (let* ((arg '(1 2 3))
188 (results (concat backtrace-tests--header
189 (backtrace-tests--result arg)))
190 (first-line (nth 0 (backtrace-tests--backtrace-lines))))
191 (backtrace-tests--make-backtrace arg)
192 (setq backtrace-insert-header-function #'backtrace-tests--insert-header)
193 (backtrace-print)
194 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
195 results))
196 ;; Move forward from header.
197 (goto-char (+ (point-min) (/ (length backtrace-tests--header) 2)))
198 (backtrace-forward-frame)
199 (should (string= (backtrace-tests--get-substring
200 (point) (+ (point) (length first-line)))
201 first-line))
202
203 (let ((start (point))
204 (offset (/ (length first-line) 2))
205 (second-line (nth 1 (backtrace-tests--backtrace-lines))))
206 ;; Move forward from start of first frame.
207 (backtrace-forward-frame)
208 (should (string= (backtrace-tests--get-substring
209 (point) (+ (point) (length second-line)))
210 second-line))
211 ;; Move forward from middle of first frame.
212 (goto-char (+ start offset))
213 (backtrace-forward-frame)
214 (should (string= (backtrace-tests--get-substring
215 (point) (+ (point) (length second-line)))
216 second-line)))
217 ;; Try to move forward from middle of last frame.
218 (goto-char (- (point-max)
219 (/ 2 (length (car (last (backtrace-tests--backtrace-lines)))))))
220 (should-error (backtrace-forward-frame))
221 ;; Try to move forward from end of buffer.
222 (goto-char (point-max))
223 (should-error (backtrace-forward-frame)))))
224
225(ert-deftest backtrace-tests--pretty-print-and-collapse ()
226 "Forms in backtrace frames can be pretty-printed and collapsed."
227 (ert-with-test-buffer (:name "pp-and-collapse")
228 (let* ((arg '(lambda (x) ; Quote this so it isn't made into a closure.
229 (let ((number (1+ x)))
230 (+ x number))))
231 (header-string "Test header: ")
232 (header (format "%s%s\n" header-string arg))
233 (insert-header-function (lambda ()
234 (insert header-string)
235 (insert (backtrace-print-to-string arg))
236 (insert "\n")))
237 (results (concat header (backtrace-tests--result arg)))
238 (last-line (format (nth (1- backtrace-tests--line-count)
239 (backtrace-tests--backtrace-lines))
240 arg))
241 (last-line-locals (format (nth (1- (* 2 backtrace-tests--line-count))
242 (backtrace-tests--backtrace-lines-with-locals))
243 arg)))
244
245 (backtrace-tests--make-backtrace arg)
246 (setq backtrace-insert-header-function insert-header-function)
247 (backtrace-print)
248 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
249 results))
250 ;; Check pp and collapse for the form in the header.
251 (goto-char (point-min))
252 (backtrace-tests--verify-pp-and-collapse header)
253 ;; Check pp and collapse for the last frame.
254 (goto-char (point-max))
255 (backtrace-backward-frame)
256 (backtrace-tests--verify-pp-and-collapse last-line)
257 ;; Check pp and collapse for local variables in the last line.
258 (goto-char (point-max))
259 (backtrace-backward-frame)
260 (backtrace-toggle-locals)
261 (forward-line)
262 (backtrace-tests--verify-pp-and-collapse last-line-locals))))
263
264(defun backtrace-tests--verify-pp-and-collapse (line)
265 "Verify that `backtrace-pretty-print' and `backtrace-collapse' work at point.
266Point should be at the beginning of a line, and LINE should be a
267string containing the text of the line at point. Assume that the
268line contains the strings \"lambda\" and \"number\"."
269 (let ((pos (point)))
270 (backtrace-pretty-print)
271 ;; Verify point is still at the start of the line.
272 (should (= pos (point))))
273
274 ;; Verify the form now spans multiple lines.
275 (let ((pos (point)))
276 (search-forward "number")
277 (should-not (= pos (point-at-bol))))
278 ;; Collapse the form.
279 (backtrace-collapse)
280 ;; Verify that the form is now back on one line,
281 ;; and that point is at the same place.
282 (should (string= (backtrace-tests--get-substring
283 (- (point) 6) (point)) "number"))
284 (should-not (= (point) (point-at-bol)))
285 (should (string= (backtrace-tests--get-substring
286 (point-at-bol) (1+ (point-at-eol)))
287 line)))
288
289(ert-deftest backtrace-tests--print-circle ()
290 "Backtrace buffers can toggle `print-circle' syntax."
291 (ert-with-test-buffer (:name "print-circle")
292 (let* ((print-circle nil)
293 (arg (let ((val (make-list 5 'a))) (nconc val val) val))
294 (results (backtrace-tests--make-regexp
295 (backtrace-tests--result arg)))
296 (results-circle (regexp-quote (let ((print-circle t))
297 (backtrace-tests--result arg))))
298 (last-frame (backtrace-tests--make-regexp
299 (format (nth (1- backtrace-tests--line-count)
300 (backtrace-tests--backtrace-lines))
301 arg)))
302 (last-frame-circle (regexp-quote
303 (let ((print-circle t))
304 (format (nth (1- backtrace-tests--line-count)
305 (backtrace-tests--backtrace-lines))
306 arg)))))
307 (backtrace-tests--make-backtrace arg)
308 (backtrace-print)
309 (should (string-match-p results
310 (backtrace-tests--get-substring (point-min) (point-max))))
311 ;; Go to the last frame.
312 (goto-char (point-max))
313 (forward-line -1)
314 ;; Turn on print-circle for that frame.
315 (backtrace-toggle-print-circle)
316 (should (string-match-p last-frame-circle
317 (backtrace-tests--get-substring (point) (point-max))))
318 ;; Turn off print-circle for the frame.
319 (backtrace-toggle-print-circle)
320 (should (string-match-p last-frame
321 (backtrace-tests--get-substring (point) (point-max))))
322 (should (string-match-p results
323 (backtrace-tests--get-substring (point-min) (point-max))))
324 ;; Turn print-circle on for the buffer.
325 (backtrace-toggle-print-circle '(4))
326 (should (string-match-p last-frame-circle
327 (backtrace-tests--get-substring (point) (point-max))))
328 (should (string-match-p results-circle
329 (backtrace-tests--get-substring (point-min) (point-max))))
330 ;; Turn print-circle off.
331 (backtrace-toggle-print-circle '(4))
332 (should (string-match-p last-frame
333 (backtrace-tests--get-substring
334 (point) (+ (point) (length last-frame)))))
335 (should (string-match-p results
336 (backtrace-tests--get-substring (point-min) (point-max)))))))
337
338(defun backtrace-tests--make-regexp (str)
339 "Make regexp from STR for `backtrace-tests--print-circle'.
340Used for results of printing circular objects without
341`print-circle' on. Look for #n in string STR where n is any
342digit and replace with #[0-9]."
343 (let ((regexp (regexp-quote str)))
344 (with-temp-buffer
345 (insert regexp)
346 (goto-char (point-min))
347 (while (re-search-forward "#[0-9]" nil t)
348 (replace-match "#[0-9]")))
349 (buffer-string)))
350
351(ert-deftest backtrace-tests--expand-ellipsis ()
352 "Backtrace buffers ellipsify large forms and can expand the ellipses."
353 ;; make a backtrace with an ellipsis
354 ;; expand the ellipsis
355 (ert-with-test-buffer (:name "variables")
356 (let* ((print-level nil)
357 (print-length nil)
358 (arg (let ((long (make-list 100 'a))
359 (deep '(0 (1 (2 (3 (4 (5 (6 (7 (8 (9))))))))))))
360 (setf (nth 1 long) deep)
361 long))
362 (results (backtrace-tests--result arg)))
363 (backtrace-tests--make-backtrace arg)
364 (backtrace-print)
365
366 ;; There should be two ellipses. Find and expand them.
367 (goto-char (point-min))
368 (search-forward "...")
369 (backward-char)
370 (push-button)
371 (search-forward "...")
372 (backward-char)
373 (push-button)
374
375 (should (string= (backtrace-tests--get-substring (point-min) (point-max))
376 results)))))
377
71(ert-deftest backtrace-tests--to-string () 378(ert-deftest backtrace-tests--to-string ()
72 (should (string= (backtrace-to-string backtrace-tests--frames) 379 "Backtraces can be produced as strings."
73 " backtrace-get-frames(nil) 380 (let ((frames (ert-with-test-buffer (:name nil)
74 (setq backtrace-tests--frames (backtrace-get-frames nil)) 381 (backtrace-tests--make-backtrace "string")
75 backtrace-tests--func1(\"string\" 0) 382 backtrace-frames)))
76 (list foo (backtrace-tests--func2 arg) (backtrace-tests--func1 arg 0)) 383 (should (string= (backtrace-to-string frames)
77 (let ((foo (list 'a arg 'b))) (list foo (backtrace-tests--func2 arg) (backtrace-tests--func1 arg 0))) 384 (backtrace-tests--result "string")))))
78 backtrace-tests--func3(\"string\")
79 backtrace-tests--create-backtrace-frames()
80")))
81 385
82(provide 'backtrace-tests) 386(defun backtrace-tests--get-substring (beg end)
387 "Return the visible text between BEG and END.
388Strip the string properties because it makes failed test results
389easier to read."
390 (substring-no-properties (filter-buffer-substring beg end)))
83 391
84;; These tests expect to see non-byte compiled stack frames. 392(provide 'backtrace-tests)
85;; Local Variables:
86;; no-byte-compile: t
87;; End:
88 393
89;;; backtrace-tests.el ends here 394;;; backtrace-tests.el ends here