mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-12-24 10:38:38 +00:00
Add tests for Edebug
* tests/lisp/emacs-lisp/edeug-tests.el: New file. * tests/lisp/emacs-lisp/edebug-resources/edebug-test-code.el: New file.
This commit is contained in:
parent
68baca3ee1
commit
0bf066d4b2
130
test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
Normal file
130
test/lisp/emacs-lisp/edebug-resources/edebug-test-code.el
Normal file
@ -0,0 +1,130 @@
|
||||
;;; edebug-test-code.el --- Sample code for the Edebug test suite
|
||||
|
||||
;; Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Gemini Lasswell
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program 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.
|
||||
;;
|
||||
;; This program 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
|
||||
;; along with this program. If not, see `http://www.gnu.org/licenses/'.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This file contains sample code used by edebug-tests.el.
|
||||
;; Before evaluation, it will be preprocessed by
|
||||
;; `edebug-tests-setup-code-file' which will remove all tags
|
||||
;; between !'s and save their positions for use by the tests.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defun edebug-test-code-fac (n)
|
||||
!start!(if !step!(< 0 n)
|
||||
(* n (edebug-test-code-fac (1- n)))!mult!
|
||||
1))
|
||||
|
||||
(defun edebug-test-code-concat (a b flag)
|
||||
!start!(if flag!flag!
|
||||
!then-start!(concat a!then-a! b!then-b!)!then-concat!
|
||||
!else-start!(concat b!else-b! a!else-a!)!else-concat!)!if!)
|
||||
|
||||
(defun edebug-test-code-range (num)
|
||||
!start!(let ((index 0)
|
||||
(result nil))
|
||||
(while (< index num)!test!
|
||||
(push index result)!loop!
|
||||
(cl-incf index))!end-loop!
|
||||
(nreverse result)))
|
||||
|
||||
(defun edebug-test-code-choices (input)
|
||||
!start!(cond
|
||||
((eq input 0) "zero")
|
||||
((eq input 7) 42)
|
||||
(t !edebug!(edebug))))
|
||||
|
||||
(defvar edebug-test-code-total nil)
|
||||
|
||||
(defun edebug-test-code-multiply (times value)
|
||||
!start!(setq edebug-test-code-total 0)
|
||||
(cl-dotimes (index times)
|
||||
(setq edebug-test-code-total (+ edebug-test-code-total value))!setq!)
|
||||
edebug-test-code-total)
|
||||
|
||||
(defun edebug-test-code-format-vector-node (node)
|
||||
!start!(concat "["
|
||||
(apply 'concat (mapcar 'edebug-test-code-format-node node))!apply!
|
||||
"]"))
|
||||
|
||||
(defun edebug-test-code-format-list-node (node)
|
||||
!start!(concat "{"
|
||||
(apply 'concat (mapcar 'edebug-test-code-format-node node))!apply!
|
||||
"}"))
|
||||
|
||||
(defun edebug-test-code-format-node (node)
|
||||
!start!(cond
|
||||
(!vectorp!(vectorp node!vnode!)!vtest! !vbefore!(edebug-test-code-format-vector-node node))
|
||||
((listp node) (edebug-test-code-format-list-node node))
|
||||
(t (format "%s" node))))
|
||||
|
||||
(defvar edebug-test-code-flavor "strawberry")
|
||||
|
||||
(defmacro edebug-test-code-with-flavor (new-flavor &rest body)
|
||||
(declare (debug (form body))
|
||||
(indent 1))
|
||||
`(let ((edebug-test-code-flavor ,new-flavor))
|
||||
,@body))
|
||||
|
||||
(defun edebug-test-code-try-flavors ()
|
||||
(let* (tried)
|
||||
(push edebug-test-code-flavor tried)
|
||||
!macro!(edebug-test-code-with-flavor "chocolate"
|
||||
(push edebug-test-code-flavor tried))
|
||||
tried)!end!)
|
||||
|
||||
(unless (featurep 'edebug-tests-nutty)!nutty!
|
||||
!setq!(setq edebug-test-code-flavor (car (edebug-test-code-try-flavors)))!end-setq!)!end-unless!
|
||||
|
||||
(cl-defgeneric edebug-test-code-emphasize (x))
|
||||
(cl-defmethod edebug-test-code-emphasize ((x integer))
|
||||
!start!(format "The number is not %s or %s, but %s!"
|
||||
(1+ x) (1- x) x))
|
||||
(cl-defmethod edebug-test-code-emphasize ((x string))
|
||||
!start!(format "***%s***" x))
|
||||
|
||||
(defun edebug-test-code-use-methods ()
|
||||
(list
|
||||
!number!(edebug-test-code-emphasize 100)
|
||||
!string!(edebug-test-code-emphasize "yes")))
|
||||
|
||||
(defun edebug-test-code-make-lambda (n)
|
||||
(lambda (x) (+ x!x! n)))
|
||||
|
||||
(defun edebug-test-code-use-lambda ()
|
||||
!start!(mapcar (edebug-test-code-make-lambda 10) '(1 2 3)))
|
||||
|
||||
(defun edebug-test-code-circular-read-syntax ()
|
||||
'(#1=a . #1#))
|
||||
|
||||
(defun edebug-test-code-hash-read-syntax ()
|
||||
!start!(list #("abcd" 1 3 (face italic))
|
||||
#x01ff))
|
||||
|
||||
(defun edebug-test-code-empty-string-list ()
|
||||
!start!(list "")!step!)
|
||||
|
||||
(defun edebug-test-code-current-buffer ()
|
||||
!start!(with-current-buffer (get-buffer-create "*edebug-test-code-buffer*")
|
||||
!body!(format "current-buffer: %s" (current-buffer))))
|
||||
|
||||
(provide 'edebug-test-code)
|
||||
;;; edebug-test-code.el ends here
|
903
test/lisp/emacs-lisp/edebug-tests.el
Normal file
903
test/lisp/emacs-lisp/edebug-tests.el
Normal file
@ -0,0 +1,903 @@
|
||||
;;; edebug-tests.el --- Edebug test suite -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Gemini Lasswell
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program 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.
|
||||
;;
|
||||
;; This program 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
|
||||
;; along with this program. If not, see `http://www.gnu.org/licenses/'.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; These tests focus on Edebug's user interface for setting
|
||||
;; breakpoints, stepping through and tracing code, and evaluating
|
||||
;; values used by the code. In addition there are some tests of
|
||||
;; Edebug's reader. There are large parts of Edebug's functionality
|
||||
;; not covered by these tests, including coverage testing, macro
|
||||
;; specifications, and the eval list buffer.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'cl-lib)
|
||||
(require 'ert)
|
||||
(require 'ert-x)
|
||||
(require 'edebug)
|
||||
(require 'kmacro)
|
||||
|
||||
;; Use `eval-and-compile' because this is used by the macro
|
||||
;; `edebug-tests-deftest'.
|
||||
(eval-and-compile
|
||||
(defvar edebug-tests-sample-code-file
|
||||
(expand-file-name
|
||||
"edebug-resources/edebug-test-code.el"
|
||||
(file-name-directory (or (bound-and-true-p byte-compile-current-file)
|
||||
load-file-name
|
||||
buffer-file-name)))
|
||||
"Name of file containing code samples for Edebug tests."))
|
||||
|
||||
(defvar edebug-tests-temp-file nil
|
||||
"Name of temp file containing sample code stripped of stop point symbols.")
|
||||
(defvar edebug-tests-stop-points nil
|
||||
"An alist of alists mapping function symbol -> stop point name -> marker.
|
||||
Used by the tests to refer to locations in `edebug-tests-temp-file'.")
|
||||
(defvar edebug-tests-messages nil
|
||||
"Messages collected during execution of the current test.")
|
||||
|
||||
(defvar edebug-tests-@-result 'no-result
|
||||
"Return value of `edebug-tests-func', or no-result if there isn't one yet.")
|
||||
|
||||
(defvar edebug-tests-failure-in-post-command nil
|
||||
"An error trapped in `edebug-tests-post-command'.
|
||||
Since `should' failures which happen inside `post-command-hook' will
|
||||
be trapped by the command loop, this preserves them until we get
|
||||
back to the top level.")
|
||||
|
||||
(defvar edebug-tests-keymap
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "@" 'edebug-tests-call-instrumented-func)
|
||||
(define-key map "C-u" 'universal-argument)
|
||||
(define-key map "C-p" 'previous-line)
|
||||
(define-key map "C-n" 'next-line)
|
||||
(define-key map "C-b" 'backward-char)
|
||||
(define-key map "C-a" 'move-beginning-of-line)
|
||||
(define-key map "C-e" 'move-end-of-line)
|
||||
(define-key map "C-k" 'kill-line)
|
||||
(define-key map "M-x" 'execute-extended-command)
|
||||
(define-key map "C-M-x" 'eval-defun)
|
||||
(define-key map "C-x X b" 'edebug-set-breakpoint)
|
||||
(define-key map "C-x X w" 'edebug-where)
|
||||
map)
|
||||
"Keys used by the keyboard macros in Edebug's tests.")
|
||||
|
||||
;;; Macros for defining tests:
|
||||
|
||||
(defmacro edebug-tests-with-default-config (&rest body)
|
||||
"Create a consistent environment for an Edebug test BODY to run in."
|
||||
(declare (debug (body)))
|
||||
`(cl-letf* (
|
||||
;; These defcustoms are set to their original value.
|
||||
(edebug-setup-hook nil)
|
||||
(edebug-all-defs nil)
|
||||
(edebug-all-forms nil)
|
||||
(edebug-eval-macro-args nil)
|
||||
(edebug-save-windows t)
|
||||
(edebug-save-displayed-buffer-points nil)
|
||||
(edebug-initial-mode 'step)
|
||||
(edebug-trace nil)
|
||||
(edebug-test-coverage nil)
|
||||
(edebug-print-length 50)
|
||||
(edebug-print-level 50)
|
||||
(edebug-print-circle t)
|
||||
(edebug-unwrap-results nil)
|
||||
(edebug-on-error t)
|
||||
(edebug-on-quit t)
|
||||
(edebug-global-break-condition nil)
|
||||
(edebug-sit-for-seconds 1)
|
||||
|
||||
;; sit-on interferes with keyboard macros.
|
||||
(edebug-sit-on-break nil)
|
||||
(edebug-continue-kbd-macro t))
|
||||
,@body))
|
||||
|
||||
(defmacro edebug-tests-with-normal-env (&rest body)
|
||||
"Set up the environment for an Edebug test BODY, run it, and clean up."
|
||||
(declare (debug (body)))
|
||||
`(edebug-tests-with-default-config
|
||||
(let ((edebug-tests-failure-in-post-command nil)
|
||||
(edebug-tests-temp-file (make-temp-file "edebug-tests-" nil ".el")))
|
||||
(edebug-tests-setup-code-file edebug-tests-temp-file)
|
||||
(ert-with-message-capture
|
||||
edebug-tests-messages
|
||||
(unwind-protect
|
||||
(with-current-buffer (find-file edebug-tests-temp-file)
|
||||
(read-only-mode)
|
||||
(setq lexical-binding t)
|
||||
(eval-buffer)
|
||||
,@body
|
||||
(when edebug-tests-failure-in-post-command
|
||||
(signal (car edebug-tests-failure-in-post-command)
|
||||
(cdr edebug-tests-failure-in-post-command))))
|
||||
(unload-feature 'edebug-test-code)
|
||||
(with-current-buffer (find-file-noselect edebug-tests-temp-file)
|
||||
(set-buffer-modified-p nil))
|
||||
(ignore-errors (kill-buffer (find-file-noselect
|
||||
edebug-tests-temp-file)))
|
||||
(ignore-errors (delete-file edebug-tests-temp-file)))))))
|
||||
|
||||
;; The following macro and its support functions implement an extension
|
||||
;; to keyboard macros to allow interleaving of keyboard macro
|
||||
;; events with evaluation of Lisp expressions. The Lisp expressions
|
||||
;; are called from within `post-command-hook', which is a strategy
|
||||
;; inspired by `kmacro-step-edit-macro'.
|
||||
|
||||
;; Some of the details necessary to get this to work with Edebug are:
|
||||
;; -- ERT's `should' macros raise errors, and errors within
|
||||
;; `post-command-hook' are trapped by the command loop. The
|
||||
;; workaround is to trap and save an error inside the hook
|
||||
;; function and reraise it after the macro exits.
|
||||
;; -- `edebug-continue-kbd-macro' must be non-nil.
|
||||
;; -- Edebug calls `exit-recursive-edit' which turns off keyboard
|
||||
;; macro execution. Solved with an advice wrapper for
|
||||
;; `exit-recursive-edit' which preserves the keyboard macro state.
|
||||
|
||||
(defmacro edebug-tests-run-kbd-macro (&rest macro)
|
||||
"Run a MACRO consisting of both keystrokes and test assertions.
|
||||
MACRO should be a list, where each item is either a keyboard
|
||||
macro segment (in string or vector form) or a Lisp expression.
|
||||
Convert the macro segments into keyboard macros and execute them.
|
||||
After the execution of the last event of each segment, evaluate
|
||||
the Lisp expressions following the segment."
|
||||
(let ((prepared (edebug-tests-prepare-macro macro)))
|
||||
`(edebug-tests-run-macro ,@prepared)))
|
||||
|
||||
;; Make support functions for edebug-tests-run-kbd-macro
|
||||
;; available at compile time.
|
||||
(eval-and-compile
|
||||
(defun edebug-tests-prepare-macro (macro)
|
||||
"Prepare a MACRO for execution.
|
||||
MACRO should be a list containing strings, vectors, and Lisp
|
||||
forms. Convert the strings and vectors to keyboard macros in
|
||||
vector representation and concatenate them to make a single
|
||||
keyboard macro. Also build a list of the same length as the
|
||||
number of events in the keyboard macro. Each item in that list
|
||||
will contain the code to evaluate after the corresponding event
|
||||
in the keyboard macro, either nil or a thunk built from the forms
|
||||
in the original list. Return a list containing the keyboard
|
||||
macro as the first item, followed by the list of thunks and/or
|
||||
nils."
|
||||
(cl-loop
|
||||
for item = (pop macro)
|
||||
while item
|
||||
for segment = (read-kbd-macro item)
|
||||
for thunk = (edebug-tests-wrap-thunk
|
||||
(cl-loop
|
||||
for form in macro
|
||||
until (or (stringp form) (vectorp form))
|
||||
collect form
|
||||
do (pop macro)))
|
||||
vconcat segment into segments
|
||||
append (edebug-tests-pad-thunk-list (length segment) thunk)
|
||||
into thunk-list
|
||||
|
||||
finally return (cons segments thunk-list)))
|
||||
|
||||
(defun edebug-tests-wrap-thunk (body)
|
||||
"If BODY is non-nil, wrap it with a lambda form."
|
||||
(when body
|
||||
`(lambda () ,@body)))
|
||||
|
||||
(defun edebug-tests-pad-thunk-list (length thunk)
|
||||
"Return a list with LENGTH elements with THUNK in the last position.
|
||||
All other elements will be nil."
|
||||
(let ((thunk-seg (make-list length nil)))
|
||||
(setf (car (last thunk-seg)) thunk)
|
||||
thunk-seg)))
|
||||
|
||||
;;; Support for test execution:
|
||||
|
||||
(defvar edebug-tests-thunks nil
|
||||
"List containing thunks to run after each command in a keyboard macro.")
|
||||
(defvar edebug-tests-kbd-macro-index nil
|
||||
"Index into `edebug-tests-run-unpacked-kbd-macro's current keyboard macro.")
|
||||
|
||||
(defun edebug-tests-run-macro (kbdmac &rest thunks)
|
||||
"Run a keyboard macro and execute a thunk after each command in it.
|
||||
KBDMAC should be a vector of events and THUNKS a list of the
|
||||
same length containing thunks and/or nils. Run the macro, and
|
||||
after the execution of every command in the macro (which may not
|
||||
be the same as every keystroke) execute the thunk at the same
|
||||
index."
|
||||
(let* ((edebug-tests-thunks thunks)
|
||||
(edebug-tests-kbd-macro-index 0)
|
||||
saved-local-map)
|
||||
(with-current-buffer (find-file-noselect edebug-tests-temp-file)
|
||||
(setq saved-local-map overriding-local-map)
|
||||
(setq overriding-local-map edebug-tests-keymap)
|
||||
(add-hook 'post-command-hook 'edebug-tests-post-command))
|
||||
(advice-add 'exit-recursive-edit
|
||||
:around 'edebug-tests-preserve-keyboard-macro-state)
|
||||
(unwind-protect
|
||||
(kmacro-call-macro nil nil nil kbdmac)
|
||||
(advice-remove 'exit-recursive-edit
|
||||
'edebug-tests-preserve-keyboard-macro-state)
|
||||
(with-current-buffer (find-file-noselect edebug-tests-temp-file)
|
||||
(setq overriding-local-map saved-local-map)
|
||||
(remove-hook 'post-command-hook 'edebug-tests-post-command)))))
|
||||
|
||||
(defun edebug-tests-preserve-keyboard-macro-state (orig &rest args)
|
||||
"Call ORIG with ARGS preserving the value of `executing-kbd-macro'.
|
||||
Useful to prevent `exit-recursive-edit' from stopping the current
|
||||
keyboard macro."
|
||||
(let ((executing-kbd-macro executing-kbd-macro))
|
||||
(apply orig args)))
|
||||
|
||||
(defun edebug-tests-post-command ()
|
||||
"Run the thunk from `edebug-tests-thunks' matching the keyboard macro index."
|
||||
(when (and edebug-tests-kbd-macro-index
|
||||
(> executing-kbd-macro-index edebug-tests-kbd-macro-index))
|
||||
(let ((thunk (nth (1- executing-kbd-macro-index) edebug-tests-thunks)))
|
||||
(when thunk
|
||||
(condition-case err
|
||||
(funcall thunk)
|
||||
(error
|
||||
(setq edebug-tests-failure-in-post-command err)
|
||||
(signal (car err) (cdr err)))))
|
||||
(setq edebug-tests-kbd-macro-index executing-kbd-macro-index))))
|
||||
|
||||
(defvar edebug-tests-func nil
|
||||
"Instrumented function used to launch Edebug.")
|
||||
(defvar edebug-tests-args nil
|
||||
"Arguments for `edebug-tests-func'.")
|
||||
|
||||
(defun edebug-tests-setup-@ (def-name args edebug-it)
|
||||
"Set up the binding for @ in `edebug-tests-keymap'.
|
||||
Find a definition for DEF-NAME in the current buffer and evaluate it.
|
||||
Set globals so that `edebug-tests-call-instrumented-func' which
|
||||
is bound to @ for edebug-tests' keyboard macros will call it with
|
||||
ARGS. EDEBUG-IT is passed through to `eval-defun'."
|
||||
(edebug-tests-locate-def def-name)
|
||||
(eval-defun edebug-it)
|
||||
(let* ((full-name (concat "edebug-test-code-" def-name))
|
||||
(sym (intern-soft full-name)))
|
||||
(should (and sym (fboundp sym)))
|
||||
(setq edebug-tests-func sym
|
||||
edebug-tests-args args)
|
||||
(setq edebug-tests-@-result 'no-result)))
|
||||
|
||||
(defun edebug-tests-call-instrumented-func ()
|
||||
"Call `edebug-tests-func' with `edebug-tests-args' and save the results."
|
||||
(interactive)
|
||||
(let ((result (apply edebug-tests-func edebug-tests-args)))
|
||||
(should (eq edebug-tests-@-result 'no-result))
|
||||
(setq edebug-tests-@-result result)))
|
||||
|
||||
(defun edebug-tests-should-be-at (def-name point-name)
|
||||
"Require that point be at the location in DEF-NAME named POINT-NAME.
|
||||
DEF-NAME should be the suffix of a definition in the code samples
|
||||
file (the part after \"edebug-tests\")."
|
||||
(let ((stop-point (edebug-tests-get-stop-point def-name point-name)))
|
||||
(should (eq (current-buffer) (find-file-noselect edebug-tests-temp-file)))
|
||||
(should (eql (point) stop-point))))
|
||||
|
||||
(defun edebug-tests-get-stop-point (def-name point-name)
|
||||
"Return the position in DEF-NAME of the stop point named POINT-NAME.
|
||||
DEF-NAME should be the suffix of a definition in the code samples
|
||||
file (the part after \"edebug-tests\")."
|
||||
(let* ((full-name (concat "edebug-test-code-" def-name))(stop-point
|
||||
(cdr (assoc point-name
|
||||
(cdr (assoc full-name edebug-tests-stop-points))))))
|
||||
(unless stop-point
|
||||
(ert-fail (format "%s not found in %s" point-name full-name)))
|
||||
stop-point))
|
||||
|
||||
(defun edebug-tests-should-match-result-in-messages (value)
|
||||
"Require that VALUE (a string) match an Edebug result in *Messages*.
|
||||
Then clear edebug-tests' saved messages."
|
||||
(should (string-match-p (concat "Result: " (regexp-quote value) "$")
|
||||
edebug-tests-messages))
|
||||
(setq edebug-tests-messages ""))
|
||||
|
||||
(defun edebug-tests-locate-def (def-name)
|
||||
"Search for a definiton of DEF-NAME from the start of the current buffer.
|
||||
Place point at the end of DEF-NAME in the buffer."
|
||||
(goto-char (point-min))
|
||||
(re-search-forward (concat "def\\S-+ edebug-test-code-" def-name)))
|
||||
|
||||
(defconst edebug-tests-start-of-next-def-regexp "^(\\S-*def\\S-+ \\(\\S-+\\)"
|
||||
"Regexp used to match the start of a definition.")
|
||||
(defconst edebug-tests-stop-point-regexp "!\\(\\S-+?\\)!"
|
||||
"Regexp used to match a stop point annotation in the sample code.")
|
||||
|
||||
;;; Set up buffer containing code samples:
|
||||
|
||||
(defmacro edebug-tests-deduplicate (name names-and-numbers)
|
||||
"Return a unique variation on NAME.
|
||||
NAME should be a string and NAMES-AND-NUMBERS an alist which can
|
||||
be used by this macro to retain state. If NAME for example is
|
||||
\"symbol\" then the first and subsequent uses of this macro will
|
||||
evaluate to \"symbol\", \"symbol-1\", \"symbol-2\", etc."
|
||||
(let ((g-name (gensym))
|
||||
(g-duplicate (gensym)))
|
||||
`(let* ((,g-name ,name)
|
||||
(,g-duplicate (assoc ,g-name ,names-and-numbers)))
|
||||
(if (null ,g-duplicate)
|
||||
(progn
|
||||
(push (cons ,g-name 0) ,names-and-numbers)
|
||||
,g-name)
|
||||
(cl-incf (cdr ,g-duplicate))
|
||||
(format "%s-%s" ,g-name (cdr ,g-duplicate))))))
|
||||
|
||||
(defun edebug-tests-setup-code-file (tmpfile)
|
||||
"Extract stop points and loadable code from the sample code file.
|
||||
Write the loadable code to a buffer for TMPFILE, and set
|
||||
`edebug-tests-stop-points' to a map from defined symbols to stop
|
||||
point names to positions in the file."
|
||||
(with-current-buffer (find-file-noselect edebug-tests-sample-code-file)
|
||||
(let ((marked-up-code (buffer-string)))
|
||||
(with-temp-file tmpfile
|
||||
(insert marked-up-code))))
|
||||
|
||||
(with-current-buffer (find-file-noselect tmpfile)
|
||||
(let ((stop-points
|
||||
;; Delete all the !name! annotations from the code, but remember
|
||||
;; their names and where they were in an alist.
|
||||
(cl-loop
|
||||
initially (goto-char (point-min))
|
||||
while (re-search-forward edebug-tests-stop-point-regexp nil t)
|
||||
for name = (match-string-no-properties 1)
|
||||
do (replace-match "")
|
||||
collect (cons name (point))))
|
||||
names-and-numbers)
|
||||
|
||||
;; Now build an alist mapping definition names to annotation
|
||||
;; names and positions.
|
||||
;; If duplicate symbols exist in the file, enter them in the
|
||||
;; alist as symbol, symbol-1, symbol-2 etc.
|
||||
(setq edebug-tests-stop-points
|
||||
(cl-loop
|
||||
initially (goto-char (point-min))
|
||||
while (re-search-forward edebug-tests-start-of-next-def-regexp
|
||||
nil t)
|
||||
for name =
|
||||
(edebug-tests-deduplicate (match-string-no-properties 1)
|
||||
names-and-numbers)
|
||||
for end-of-def =
|
||||
(save-match-data
|
||||
(save-excursion
|
||||
(re-search-forward edebug-tests-start-of-next-def-regexp
|
||||
nil 0)
|
||||
(point)))
|
||||
collect (cons name
|
||||
(cl-loop
|
||||
while (and stop-points
|
||||
(< (cdar stop-points) end-of-def))
|
||||
collect (pop stop-points))))))))
|
||||
|
||||
;;; Tests
|
||||
|
||||
(ert-deftest edebug-tests-check-keymap ()
|
||||
"Verify that `edebug-mode-map' is compatible with these tests.
|
||||
If this test fails, one of two things is true. Either your
|
||||
customizations modify `edebug-mode-map', in which case starting
|
||||
Emacs with the -Q flag should fix the problem, or
|
||||
`edebug-mode-map' has changed in edebug.el, in which case this
|
||||
test and possibly others should be updated."
|
||||
;; The reason verify-keybinding is a macro instead of a function is
|
||||
;; that in the event of a failure, it makes the keybinding that
|
||||
;; failed show up in ERT's output.
|
||||
(cl-macrolet ((verify-keybinding (key binding)
|
||||
`(should (eq (lookup-key edebug-mode-map ,key)
|
||||
,binding))))
|
||||
(verify-keybinding " " 'edebug-step-mode)
|
||||
(verify-keybinding "n" 'edebug-next-mode)
|
||||
(verify-keybinding "g" 'edebug-go-mode)
|
||||
(verify-keybinding "G" 'edebug-Go-nonstop-mode)
|
||||
(verify-keybinding "t" 'edebug-trace-mode)
|
||||
(verify-keybinding "T" 'edebug-Trace-fast-mode)
|
||||
(verify-keybinding "c" 'edebug-continue-mode)
|
||||
(verify-keybinding "C" 'edebug-Continue-fast-mode)
|
||||
(verify-keybinding "f" 'edebug-forward-sexp)
|
||||
(verify-keybinding "h" 'edebug-goto-here)
|
||||
(verify-keybinding "I" 'edebug-instrument-callee)
|
||||
(verify-keybinding "i" 'edebug-step-in)
|
||||
(verify-keybinding "o" 'edebug-step-out)
|
||||
(verify-keybinding "q" 'top-level)
|
||||
(verify-keybinding "Q" 'edebug-top-level-nonstop)
|
||||
(verify-keybinding "a" 'abort-recursive-edit)
|
||||
(verify-keybinding "S" 'edebug-stop)
|
||||
(verify-keybinding "b" 'edebug-set-breakpoint)
|
||||
(verify-keybinding "u" 'edebug-unset-breakpoint)
|
||||
(verify-keybinding "B" 'edebug-next-breakpoint)
|
||||
(verify-keybinding "x" 'edebug-set-conditional-breakpoint)
|
||||
(verify-keybinding "X" 'edebug-set-global-break-condition)
|
||||
(verify-keybinding "r" 'edebug-previous-result)
|
||||
(verify-keybinding "e" 'edebug-eval-expression)
|
||||
(verify-keybinding "\C-x\C-e" 'edebug-eval-last-sexp)
|
||||
(verify-keybinding "E" 'edebug-visit-eval-list)
|
||||
(verify-keybinding "w" 'edebug-where)
|
||||
(verify-keybinding "v" 'edebug-view-outside) ;; maybe obsolete??
|
||||
(verify-keybinding "p" 'edebug-bounce-point)
|
||||
(verify-keybinding "P" 'edebug-view-outside) ;; same as v
|
||||
(verify-keybinding "W" 'edebug-toggle-save-windows)
|
||||
(verify-keybinding "?" 'edebug-help)
|
||||
(verify-keybinding "d" 'edebug-backtrace)
|
||||
(verify-keybinding "-" 'negative-argument)
|
||||
(verify-keybinding "=" 'edebug-temp-display-freq-count)))
|
||||
|
||||
(ert-deftest edebug-tests-stop-point-at-start-of-first-instrumented-function ()
|
||||
"Edebug stops at the beginning of an instrumented function."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "fac" '(0) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "fac" "start")
|
||||
"SPC" (edebug-tests-should-be-at "fac" "step")
|
||||
"g" (should (equal edebug-tests-@-result 1)))))
|
||||
|
||||
(ert-deftest edebug-tests-step-showing-evaluation-results ()
|
||||
"Edebug prints expression evaluation results to the echo area."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "concat" '("x" "y" nil) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "concat" "start")
|
||||
"SPC" (edebug-tests-should-be-at "concat" "flag")
|
||||
(edebug-tests-should-match-result-in-messages "nil")
|
||||
"SPC" (edebug-tests-should-be-at "concat" "else-start")
|
||||
"SPC" (edebug-tests-should-be-at "concat" "else-b")
|
||||
(edebug-tests-should-match-result-in-messages "\"y\"")
|
||||
"SPC" (edebug-tests-should-be-at "concat" "else-a")
|
||||
(edebug-tests-should-match-result-in-messages "\"x\"")
|
||||
"SPC" (edebug-tests-should-be-at "concat" "else-concat")
|
||||
(edebug-tests-should-match-result-in-messages "\"yx\"")
|
||||
"SPC" (edebug-tests-should-be-at "concat" "if")
|
||||
(edebug-tests-should-match-result-in-messages "\"yx\"")
|
||||
"SPC" (should (equal edebug-tests-@-result "yx")))))
|
||||
|
||||
(ert-deftest edebug-tests-set-breakpoint-at-point ()
|
||||
"Edebug can set a breakpoint at point."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "concat" '("x" "y" t) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "concat" "start")
|
||||
"C-n C-e b C-n" ; Move down, set a breakpoint and move away.
|
||||
"g" (edebug-tests-should-be-at "concat" "then-concat")
|
||||
(edebug-tests-should-match-result-in-messages "\"xy\"")
|
||||
"g" (should (equal edebug-tests-@-result "xy")))))
|
||||
|
||||
(ert-deftest edebug-tests-set-temporary-breakpoint-at-point ()
|
||||
"Edebug can set a temporary breakpoint at point."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "range" '(3) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "range" "start")
|
||||
"C-n C-n C-n C-e" ; Move down to the end of a sexp in the loop.
|
||||
"C-u b" ; Set a temporary breakpoint.
|
||||
"C-n" ; Move away.
|
||||
"g" (edebug-tests-should-be-at "range" "loop")
|
||||
(edebug-tests-should-match-result-in-messages "(0)")
|
||||
"g" (should (equal edebug-tests-@-result '(0 1 2))))))
|
||||
|
||||
(ert-deftest edebug-tests-clear-breakpoint ()
|
||||
"Edebug can clear a breakpoint."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "range" '(3) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@"
|
||||
(message "after @")
|
||||
(edebug-tests-should-be-at "range" "start")
|
||||
"C-n C-n C-n C-e b C-n" ; Move down, set a breakpoint and move away.
|
||||
"g" (edebug-tests-should-be-at "range" "loop")
|
||||
(edebug-tests-should-match-result-in-messages "(0)")
|
||||
"g" (edebug-tests-should-be-at "range" "loop")
|
||||
(edebug-tests-should-match-result-in-messages "(1 0)")
|
||||
"u" ; Unset the breakpoint.
|
||||
"g" (should (equal edebug-tests-@-result '(0 1 2))))))
|
||||
|
||||
(ert-deftest edebug-tests-move-point-to-next-breakpoint ()
|
||||
"Edebug can move point to the next breakpoint."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "concat" '("a" "b" nil) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "concat" "start")
|
||||
"C-n C-e b" ; Move down, set a breakpoint.
|
||||
"C-n b" ; Set another breakpoint on the next line.
|
||||
"C-p C-p C-p" ; Move back up.
|
||||
"B" (edebug-tests-should-be-at "concat" "then-concat")
|
||||
"B" (edebug-tests-should-be-at "concat" "else-concat")
|
||||
"G" (should (equal edebug-tests-@-result "ba")))))
|
||||
|
||||
(ert-deftest edebug-tests-move-point-back-to-stop-point ()
|
||||
"Edebug can move point back to a stop point."
|
||||
(edebug-tests-with-normal-env
|
||||
(let ((test-buffer (get-buffer-create "edebug-tests-temp")))
|
||||
(edebug-tests-setup-@ "fac" '(4) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "fac" "start")
|
||||
"C-n w" (edebug-tests-should-be-at "fac" "start")
|
||||
(pop-to-buffer test-buffer)
|
||||
"C-x X w" (edebug-tests-should-be-at "fac" "start")
|
||||
"g" (should (equal edebug-tests-@-result 24)))
|
||||
(ignore-errors (kill-buffer test-buffer)))))
|
||||
|
||||
(ert-deftest edebug-tests-jump-to-point ()
|
||||
"Edebug can stop at a temporary breakpoint at point."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "range" '(3) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "range" "start")
|
||||
"C-n C-n C-n C-e" ; Move down to the end of a sexp in the loop.
|
||||
"h" (edebug-tests-should-be-at "range" "loop")
|
||||
(edebug-tests-should-match-result-in-messages "(0)")
|
||||
"g" (should (equal edebug-tests-@-result '(0 1 2))))))
|
||||
|
||||
(ert-deftest edebug-tests-jump-forward-one-sexp ()
|
||||
"Edebug can run the program for one expression."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "range" '(3) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "range" "start")
|
||||
"SPC SPC f" (edebug-tests-should-be-at "range" "test")
|
||||
"g" (should (equal edebug-tests-@-result '(0 1 2))))))
|
||||
|
||||
(ert-deftest edebug-tests-run-out-of-containing-sexp ()
|
||||
"Edebug can run the program until the end of the containing sexp."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "range" '(3) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "range" "start")
|
||||
"SPC SPC f" (edebug-tests-should-be-at "range" "test")
|
||||
"o" (edebug-tests-should-be-at "range" "end-loop")
|
||||
(edebug-tests-should-match-result-in-messages "nil")
|
||||
"g" (should (equal edebug-tests-@-result '(0 1 2))))))
|
||||
|
||||
(ert-deftest edebug-tests-observe-breakpoint-in-source ()
|
||||
"Edebug will stop at a breakpoint embedded in source code."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "choices" '(8) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "choices" "start")
|
||||
"g" (edebug-tests-should-be-at "choices" "edebug")
|
||||
"g" (should (equal edebug-tests-@-result nil)))))
|
||||
|
||||
(ert-deftest edebug-tests-set-conditional-breakpoint ()
|
||||
"Edebug can set and observe a conditional breakpoint."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "fac" '(5) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "fac" "start")
|
||||
;; Set conditional breakpoint at end of next line.
|
||||
"C-n C-e x (eql SPC n SPC 3) RET"
|
||||
"g" (edebug-tests-should-be-at "fac" "mult")
|
||||
(edebug-tests-should-match-result-in-messages "6 (#o6, #x6, ?\\C-f)")
|
||||
"g" (should (equal edebug-tests-@-result 120)))))
|
||||
|
||||
(ert-deftest edebug-tests-error-trying-to-set-breakpoint-in-uninstrumented-code
|
||||
()
|
||||
"Edebug refuses to set a breakpoint in uninsented code."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "fac" '(5) t)
|
||||
(let* ((debug-on-error nil)
|
||||
(edebug-on-error nil)
|
||||
error-message
|
||||
(command-error-function (lambda (&rest args)
|
||||
(setq error-message (cadar args)))))
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "fac" "start")
|
||||
"C-u 10 C-n" ; Move down and out of instrumented function.
|
||||
"b" (should (string-match-p "Not inside instrumented form"
|
||||
error-message))
|
||||
;; The error stopped the keyboard macro. Start it again.
|
||||
(should-not executing-kbd-macro)
|
||||
(setq executing-kbd-macro t)
|
||||
"g"))))
|
||||
|
||||
(ert-deftest edebug-tests-set-and-break-on-global-condition ()
|
||||
"Edebug can break when a global condition becomes true."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "multiply" '(5 3) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "multiply" "start")
|
||||
"X (> SPC edebug-test-code-total SPC 10) RET"
|
||||
(should edebug-global-break-condition)
|
||||
"g" (edebug-tests-should-be-at "multiply" "setq")
|
||||
(should (eql (symbol-value 'edebug-test-code-total) 12))
|
||||
"X C-a C-k nil RET" ; Remove suggestion before entering nil.
|
||||
"g" (should (equal edebug-tests-@-result 15)))))
|
||||
|
||||
(ert-deftest edebug-tests-trace-showing-results-at-stop-points ()
|
||||
"Edebug can trace execution, showing results at stop points."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "concat" '("x" "y" nil) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "concat" "start")
|
||||
"T" (should (string-match-p
|
||||
(concat "Result: nil\n.*?"
|
||||
"Result: \"y\"\n.*?"
|
||||
"Result: \"x\"\n.*?"
|
||||
"Result: \"yx\"\n.*?"
|
||||
"Result: \"yx\"\n")
|
||||
edebug-tests-messages))
|
||||
(should (equal edebug-tests-@-result "yx")))))
|
||||
|
||||
(ert-deftest edebug-tests-trace-showing-results-at-breakpoints ()
|
||||
"Edebug can trace execution, showing results at breakpoints."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-locate-def "format-vector-node")
|
||||
(edebug-tests-run-kbd-macro "C-u C-M-x C-n C-n C-e C-x X b")
|
||||
(edebug-tests-locate-def "format-list-node")
|
||||
(edebug-tests-run-kbd-macro "C-u C-M-x C-n C-n C-e C-x X b")
|
||||
(edebug-tests-setup-@ "format-node" '(([a b] [c d])) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "format-node" "start")
|
||||
"C" (should (string-match-p
|
||||
(concat "Result: \"ab\"\n.*?"
|
||||
"Result: \"cd\"\n.*?"
|
||||
"Result: \"\\[ab]\\[cd]\"\n")
|
||||
edebug-tests-messages))
|
||||
(should (equal edebug-tests-@-result "{[ab][cd]}")))))
|
||||
|
||||
(ert-deftest edebug-tests-trace-function-call-and-return ()
|
||||
"Edebug can create a trace of function calls and returns."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-locate-def "format-vector-node")
|
||||
(eval-defun t)
|
||||
(edebug-tests-locate-def "format-list-node")
|
||||
(eval-defun t)
|
||||
(edebug-tests-setup-@ "format-node" '((a [b])) t)
|
||||
(let ((edebug-trace t)
|
||||
(trace-start (with-current-buffer
|
||||
(get-buffer-create edebug-trace-buffer) (point-max))))
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "format-node" "start")
|
||||
"g" (should (equal edebug-tests-@-result "{a[b]}")))
|
||||
(with-current-buffer edebug-trace-buffer
|
||||
(should (string=
|
||||
"{ edebug-test-code-format-node args: ((a [b]))
|
||||
:{ edebug-test-code-format-list-node args: ((a [b]))
|
||||
::{ edebug-test-code-format-node args: (a)
|
||||
::} edebug-test-code-format-node result: a
|
||||
::{ edebug-test-code-format-node args: ([b])
|
||||
:::{ edebug-test-code-format-vector-node args: ([b])
|
||||
::::{ edebug-test-code-format-node args: (b)
|
||||
::::} edebug-test-code-format-node result: b
|
||||
:::} edebug-test-code-format-vector-node result: [b]
|
||||
::} edebug-test-code-format-node result: [b]
|
||||
:} edebug-test-code-format-list-node result: {a[b]}
|
||||
} edebug-test-code-format-node result: {a[b]}
|
||||
" (buffer-substring trace-start (point-max))))))))
|
||||
|
||||
(ert-deftest edebug-tests-evaluate-expressions ()
|
||||
"Edebug can evaluate an expression in the context outside of itself."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "range" '(2) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "range" "start")
|
||||
"SPC SPC f" (edebug-tests-should-be-at "range" "test")
|
||||
(edebug-tests-should-match-result-in-messages "t")
|
||||
"e (- SPC num SPC index) RET"
|
||||
;; Edebug just prints the result without "Result:"
|
||||
(should (string-match-p
|
||||
(regexp-quote "2 (#o2, #x2, ?\\C-b)")
|
||||
edebug-tests-messages))
|
||||
"g" (should (equal edebug-tests-@-result '(0 1))))
|
||||
|
||||
;; Do it again with lexical-binding turned off.
|
||||
(setq lexical-binding nil)
|
||||
(eval-buffer)
|
||||
(should-not lexical-binding)
|
||||
(edebug-tests-setup-@ "range" '(2) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "range" "start")
|
||||
"SPC SPC f" (edebug-tests-should-be-at "range" "test")
|
||||
(edebug-tests-should-match-result-in-messages "t")
|
||||
"e (- SPC num SPC index) RET"
|
||||
;; Edebug just prints the result without "Result:"
|
||||
(should (string-match-p
|
||||
(regexp-quote "2 (#o2, #x2, ?\\C-b)")
|
||||
edebug-tests-messages))
|
||||
"g" (should (equal edebug-tests-@-result '(0 1))))))
|
||||
|
||||
(ert-deftest edebug-tests-step-into-function ()
|
||||
"Edebug can step into a function."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "format-node" '([b]) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "format-node" "start")
|
||||
"SPC SPC SPC SPC"
|
||||
(edebug-tests-should-be-at "format-node" "vbefore")
|
||||
"i" (edebug-tests-should-be-at "format-vector-node" "start")
|
||||
"g" (should (equal edebug-tests-@-result "[b]")))))
|
||||
|
||||
(ert-deftest edebug-tests-error-stepping-into-subr ()
|
||||
"Edebug refuses to step into a C function."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "format-node" '([b]) t)
|
||||
(let* ((debug-on-error nil)
|
||||
(edebug-on-error nil)
|
||||
error-message
|
||||
(command-error-function (lambda (&rest args)
|
||||
(setq error-message (cl-cadar args)))))
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "format-node" "start")
|
||||
"SPC" (edebug-tests-should-be-at "format-node" "vectorp")
|
||||
"i" (should (string-match-p "vectorp is a built-in function"
|
||||
error-message))
|
||||
;; The error stopped the keyboard macro. Start it again.
|
||||
(should-not executing-kbd-macro)
|
||||
(setq executing-kbd-macro t)
|
||||
"g" (should (equal edebug-tests-@-result "[b]"))))))
|
||||
|
||||
(ert-deftest edebug-tests-step-into-macro-error ()
|
||||
"Edebug gives an error on trying to step into a macro (Bug#26847)."
|
||||
:expected-result :failed
|
||||
(ert-fail "Forcing failure because letting this test run aborts the others.")
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "try-flavors" nil t)
|
||||
(let* ((debug-on-error nil)
|
||||
(edebug-on-error nil)
|
||||
(error-message "")
|
||||
(command-error-function (lambda (&rest args)
|
||||
(setq error-message (cl-cadar args)))))
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@ SPC SPC SPC SPC SPC"
|
||||
(edebug-tests-should-be-at "try-flavors" "macro")
|
||||
"i" (should (string-match-p "edebug-test-code-try-flavors is a macro"
|
||||
error-message))
|
||||
;; The error stopped the keyboard macro. Start it again.
|
||||
(should-not executing-kbd-macro)
|
||||
(setq executing-kbd-macro t)
|
||||
"g" (should (equal edebug-tests-@-result
|
||||
'("chocolate" "strawberry")))))))
|
||||
|
||||
(ert-deftest edebug-tests-step-into-generic-method ()
|
||||
"Edebug can step into a generic method (Bug#22294)."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "use-methods" nil t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@ SPC" (edebug-tests-should-be-at "use-methods" "number")
|
||||
"i" (edebug-tests-should-be-at "emphasize-1" "start")
|
||||
"gg" (should (equal edebug-tests-@-result
|
||||
'("The number is not 101 or 99, but 100!"
|
||||
"***yes***"))))))
|
||||
|
||||
(ert-deftest edebug-tests-break-in-lambda-out-of-defining-context ()
|
||||
"Edebug observes a breakpoint in a lambda executed out of defining context."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-locate-def "make-lambda")
|
||||
(eval-defun t)
|
||||
(goto-char (edebug-tests-get-stop-point "make-lambda" "x"))
|
||||
(edebug-set-breakpoint t)
|
||||
(edebug-tests-setup-@ "use-lambda" nil t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@g" (edebug-tests-should-be-at "make-lambda" "x")
|
||||
(edebug-tests-should-match-result-in-messages "1 (#o1, #x1, ?\\C-a)")
|
||||
"g" (should (equal edebug-tests-@-result '(11 12 13))))))
|
||||
|
||||
(ert-deftest edebug-tests-respects-initial-mode ()
|
||||
"Edebug can stop first at breakpoint instead of first instrumented function."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "fac" '(4) t)
|
||||
(goto-char (edebug-tests-get-stop-point "fac" "mult"))
|
||||
(edebug-set-breakpoint t)
|
||||
(setq edebug-initial-mode 'go)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "fac" "mult")
|
||||
(edebug-tests-should-match-result-in-messages "1 (#o1, #x1, ?\\C-a)")
|
||||
"G" (should (equal edebug-tests-@-result 24)))))
|
||||
|
||||
(ert-deftest edebug-tests-step-through-non-definition ()
|
||||
"Edebug can step through a non-defining form."
|
||||
(edebug-tests-with-normal-env
|
||||
(goto-char (edebug-tests-get-stop-point "try-flavors" "end-unless"))
|
||||
(edebug-tests-run-kbd-macro
|
||||
"C-u C-M-x"
|
||||
"SPC SPC" (edebug-tests-should-be-at "try-flavors" "nutty")
|
||||
(edebug-tests-should-match-result-in-messages "nil")
|
||||
"SPC" (edebug-tests-should-be-at "try-flavors" "setq")
|
||||
"f" (edebug-tests-should-be-at "try-flavors" "end-setq")
|
||||
(edebug-tests-should-match-result-in-messages "\"chocolate\"")
|
||||
"g")))
|
||||
|
||||
(ert-deftest edebug-tests-conditional-breakpoints-can-use-lexical-variables ()
|
||||
"Edebug can set a conditional breakpoint using a lexical variable. Bug#12685"
|
||||
(edebug-tests-with-normal-env
|
||||
(should lexical-binding)
|
||||
(edebug-tests-setup-@ "fac" '(5) t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at "fac" "start")
|
||||
;; Set conditional breakpoint at end of next line.
|
||||
"C-n C-e x (eql SPC n SPC 3) RET"
|
||||
"g" (edebug-tests-should-be-at "fac" "mult")
|
||||
(edebug-tests-should-match-result-in-messages
|
||||
"6 (#o6, #x6, ?\\C-f)"))))
|
||||
|
||||
(ert-deftest edebug-tests-writable-buffer-state-is-preserved ()
|
||||
"On Edebug exit writable buffers are still writable (Bug#14144)."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "choices" '(0) t)
|
||||
(read-only-mode -1)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@g" (should (equal edebug-tests-@-result "zero")))
|
||||
(barf-if-buffer-read-only)))
|
||||
|
||||
(ert-deftest edebug-tests-list-containing-empty-string-result-printing ()
|
||||
"Edebug correctly prints a list containing only an empty string (Bug#17934)."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "empty-string-list" nil t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@ SPC" (edebug-tests-should-be-at
|
||||
"empty-string-list" "step")
|
||||
(edebug-tests-should-match-result-in-messages "(\"\")")
|
||||
"g")))
|
||||
|
||||
(ert-deftest edebug-tests-evaluation-of-current-buffer-bug-19611 ()
|
||||
"Edebug can evaluate `current-buffer' in correct context. (Bug#19611)."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "current-buffer" nil t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (edebug-tests-should-be-at
|
||||
"current-buffer" "start")
|
||||
"SPC SPC SPC" (edebug-tests-should-be-at
|
||||
"current-buffer" "body")
|
||||
"e (current-buffer) RET"
|
||||
;; Edebug just prints the result without "Result:"
|
||||
(should (string-match-p
|
||||
(regexp-quote "*edebug-test-code-buffer*")
|
||||
edebug-tests-messages))
|
||||
"g" (should (equal edebug-tests-@-result
|
||||
"current-buffer: *edebug-test-code-buffer*")))))
|
||||
|
||||
(ert-deftest edebug-tests-trivial-backquote ()
|
||||
"Edebug can instrument a trivial backquote expression (Bug#23651)."
|
||||
(edebug-tests-with-normal-env
|
||||
(read-only-mode -1)
|
||||
(delete-region (point-min) (point-max))
|
||||
(insert "`1")
|
||||
(read-only-mode)
|
||||
(edebug-eval-defun nil)
|
||||
(should (string-match-p (regexp-quote "1 (#o1, #x1, ?\\C-a)")
|
||||
edebug-tests-messages))
|
||||
(setq edebug-tests-messages "")
|
||||
|
||||
(setq edebug-initial-mode 'go)
|
||||
;; In Bug#23651 Edebug would hang reading `1.
|
||||
(edebug-eval-defun t)))
|
||||
|
||||
(ert-deftest edebug-tests-trivial-comma ()
|
||||
"Edebug can read a trivial comma expression (Bug#23651)."
|
||||
(edebug-tests-with-normal-env
|
||||
(read-only-mode -1)
|
||||
(delete-region (point-min) (point-max))
|
||||
(insert ",1")
|
||||
(read-only-mode)
|
||||
(should-error (edebug-eval-defun t))))
|
||||
|
||||
(ert-deftest edebug-tests-circular-read-syntax ()
|
||||
"Edebug can instrument code using circular read object syntax (Bug#23660)."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "circular-read-syntax" nil t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@" (should (eql (car edebug-tests-@-result)
|
||||
(cdr edebug-tests-@-result))))))
|
||||
|
||||
(ert-deftest edebug-tests-hash-read-syntax ()
|
||||
"Edebug can instrument code which uses # read syntax (Bug#25068)."
|
||||
(edebug-tests-with-normal-env
|
||||
(edebug-tests-setup-@ "hash-read-syntax" nil t)
|
||||
(edebug-tests-run-kbd-macro
|
||||
"@g" (should (equal edebug-tests-@-result
|
||||
'(#("abcd" 1 3 (face italic)) 511))))))
|
||||
|
||||
(provide 'edebug-tests)
|
||||
;;; edebug-tests.el ends here
|
Loading…
Reference in New Issue
Block a user