[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/pgtk 30ac6fb: Merge remote-tracking branch 'origin/master' into

From: Po Lu
Subject: feature/pgtk 30ac6fb: Merge remote-tracking branch 'origin/master' into feature/pgtk
Date: Tue, 14 Dec 2021 04:43:27 -0500 (EST)

branch: feature/pgtk
commit 30ac6fbbed95b3e9db530a35be7d04c257076423
Merge: da2c0e8 8c0f9be
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Merge remote-tracking branch 'origin/master' into feature/pgtk
 .gitignore                          |   1 +
 admin/notes/emba                    |   4 +
 doc/lispref/functions.texi          |   7 +-
 doc/lispref/windows.texi            | 214 ++++++++++++++++++++----------------
 etc/NEWS                            |   7 ++
 etc/NEWS.28                         |   6 +-
 lisp/calc/calc.el                   |   2 +-
 lisp/completion.el                  |   4 +-
 lisp/emacs-lisp/ert.el              | 134 +++++++++++++++++++++-
 lisp/emacs-lisp/generator.el        |   6 +-
 lisp/eshell/esh-cmd.el              |   4 +-
 lisp/help-macro.el                  |   8 +-
 lisp/ielm.el                        |  38 +++----
 lisp/international/robin.el         |   8 +-
 lisp/pcomplete.el                   |  14 +--
 lisp/progmodes/python.el            |   4 +-
 lisp/progmodes/xscheme.el           |   5 +-
 lisp/tab-bar.el                     |   2 +-
 make-dist                           |  11 +-
 src/bignum.c                        |   9 ++
 src/sqlite.c                        |  38 ++++++-
 src/xdisp.c                         |  11 +-
 test/Makefile.in                    |   1 +
 test/README                         |   3 +
 test/infra/Makefile.in              |   6 +-
 test/infra/gitlab-ci.yml            |  22 ++--
 test/infra/test-jobs.yml            |   1 +
 test/lisp/progmodes/python-tests.el |  18 ++-
 test/src/sqlite-tests.el            |  32 ++++++
 29 files changed, 430 insertions(+), 190 deletions(-)

diff --git a/.gitignore b/.gitignore
index 25ed3bd..78557a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -159,6 +159,7 @@ test/manual/etags/CTAGS
 # ctags, etags.
diff --git a/admin/notes/emba b/admin/notes/emba
index f1b52b2..2135c7a 100644
--- a/admin/notes/emba
+++ b/admin/notes/emba
@@ -63,6 +63,10 @@ They can be downloaded from the server, visiting the URL
 <https://emba.gnu.org/emacs/emacs/-/pipelines>, and selecting the job
 in question.
+Every pipeline generates a JUnit test report for the respective test
+jobs, which can be inspected on the pipeline web page.  This test
+report counts completed ERT tests, aborted tests are not counted.
 * Emba configuration
 The emba configuration files are hosted on
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index 9c1fde0..46a1e57 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -1647,9 +1647,10 @@ function will be interactive and will use the 
interactive spec of
 @var{function}.  One exception: if the interactive spec of @var{function}
 is a function (i.e., a @code{lambda} expression or an @code{fbound}
 symbol rather than an expression or a string), then the interactive
-spec of the combined function will be a call to that function with as sole
-argument the interactive spec of the original function.  To interpret the spec
-received as argument, use @code{advice-eval-interactive-spec}.
+spec of the combined function will be a call to that function with
+the interactive spec of the original function as sole argument.  To
+interpret the spec received as argument, use
 Note: The interactive spec of @var{function} will apply to the combined
 function and should hence obey the calling convention of the combined function
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 395b88e..c3894bc 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -4229,97 +4229,48 @@ action alist entry (@pxref{Buffer Display Action 
 @node Quitting Windows
 @section Quitting Windows
-When you want to get rid of a window used for displaying a buffer, you
-can call @code{delete-window} or @code{delete-windows-on}
-(@pxref{Deleting Windows}) to remove that window from its frame.  If the
-buffer is shown on a separate frame, you might want to call
-@code{delete-frame} (@pxref{Deleting Frames}) instead.  If, on the other
-hand, a window has been reused for displaying the buffer, you might
-prefer showing the buffer previously shown in that window, by calling the
-function @code{switch-to-prev-buffer} (@pxref{Window History}).
-Finally, you might want to either bury (@pxref{Buffer List}) or kill
-(@pxref{Killing Buffers}) the window's buffer.
-   The following command uses information on how the window for
-displaying the buffer was obtained in the first place, thus attempting
-to automate the above decisions for you.
+@cindex quitting windows
+After a command uses @code{display-buffer} to put a buffer on the
+screen, the user may decide to hide it and return to the previous
+configuration of the Emacs display.  We call that @dfn{quitting the
+window}.  The way to do this is to call @code{quit-window} while the
+window used by @code{display-buffer} is the selected window.
+The right way to restore the previous configuration of the display
+depends on what was done to the window where the buffer now appears.
+It might be right to delete that window, or delete its frame, or just
+display another buffer in that window.  One complication is that the
+user may have changed the window configuration since the act of
+displaying that buffer, and it would be undesirable to undo the user's
+explicitly requested changes.
+To enable @code{quit-window} to do the right thing,
+@code{display-buffer} saves information about what it did in the
+window's @code{quit-restore} parameter (@pxref{Window Parameters}).
 @deffn Command quit-window &optional kill window
 This command quits @var{window} and buries its buffer.  The argument
 @var{window} must be a live window and defaults to the selected one.
 With prefix argument @var{kill} non-@code{nil}, it kills the buffer
-instead of burying it.  It calls the function @code{quit-restore-window}
-described next to deal with the window and its buffer.
+instead of burying it.
 @vindex quit-window-hook
-The functions in @code{quit-window-hook} are run before doing anything
+The function @code{quit-window} first runs @code{quit-window-hook}.
+Then it calls the function @code{quit-restore-window}, described next,
+which does the hard work.
 @end deffn
+You can get more control by calling @code{quit-restore-window} instead.
 @defun quit-restore-window &optional window bury-or-kill
 This function handles @var{window} and its buffer after quitting.  The
 optional argument @var{window} must be a live window and defaults to
-the selected one. The function's behavior is determined by the four
-elements of the list specified by @var{window}'s @code{quit-restore}
-parameter (@pxref{Window Parameters}).
-The first element of the @code{quit-restore} parameter is one of the
-symbols @code{window}, meaning that the window has been specially
-created by @code{display-buffer}; @code{frame}, a separate frame has
-been created; @code{same}, the window has only ever displayed this
-buffer; or @code{other}, the window showed another buffer before.
-@code{frame} and @code{window} affect how the window is quit, while
-@code{same} and @code{other} affect the redisplay of buffers
-previously shown in @var{window}.
-The parameter's second element is either one of the symbols
-@code{window} or @code{frame}, or a list whose elements are the buffer
-shown in @var{window} before, that buffer's window start and window
-point positions, and @var{window}'s height at that time.  If that
-buffer is still live when @var{window} is quit, then this function may
-reuse @var{window} to display it.
-The third element is the window selected at the time the parameter was
-created.  If this function deletes @var{window}, it subsequently tries
-to reselect the window named by that element.
-The fourth element is the buffer whose display caused the creation of
-this parameter.  This function may delete @var{window} if and only if
-it still shows that buffer.
-This function will try to delete @var{window} if and only if (1) the
-first element of its @code{quit-restore} parameter is either
-@code{window} or @code{frame}, (2) the window has no history of
-previously-displayed buffers and (3) the fourth element of the
-@code{quit-restore} parameter specifies the buffer currently displayed
-in @var{window}.  If @var{window} is part of an atomic window
-(@pxref{Atomic Windows}), it will try to delete the root of that
-atomic window instead.  In either case, it tries to avoid signaling an
-error when @var{window} cannot be deleted.
-If @var{window} shall be deleted, is the only window on its frame and
-there are other frames on that frame's terminal, the value of the
-optional argument @var{bury-or-kill} determines how to proceed with
-the window.  If @var{bury-or-kill} equals @code{kill}, the frame is
-deleted unconditionally.  Otherwise, the fate of the frame is
-determined by calling @code{frame-auto-hide-function} (see below) with
-that frame as sole argument.
-If the second element of the @code{quit-restore} parameter is a list
-of a buffer, a window start (@pxref{Window Start and End}) and a
-window point (@pxref{Window Point}), and that buffer is still live,
-the buffer will be displayed, and start and point set accordingly.
-If, in addition, @var{window}'s buffer was temporarily resized, this
-function will also try to restore the original height of @var{window}.
-Otherwise, if @var{window} was previously used for displaying other
-buffers (@pxref{Window History}), the most recent buffer in that
-history will be displayed.  In either case, if @var{window} is not
-deleted, its @code{quit-restore} parameter is reset to @code{nil}.
+the selected one.  The function takes account of the @var{window}'s
+@code{quit-restore} parameter.
 The optional argument @var{bury-or-kill} specifies how to deal with
-@var{window}'s buffer.  The following values are handled:
+@var{window}'s buffer.  The following values are meaningful:
 @table @code
 @item nil
@@ -4329,25 +4280,106 @@ consequence, if @var{window} is not deleted, invoking
 @item append
 This means that if @var{window} is not deleted, its buffer is moved to
-the end of @var{window}'s list of previous buffers, so it's less likely
-that a future invocation of @code{switch-to-prev-buffer} will switch to
-it.  Also, it moves the buffer to the end of the frame's buffer list.
+the end of @var{window}'s list of previous buffers (@pxref{Window
+History}), so it's less likely that future invocations of
+@code{switch-to-prev-buffer} will switch to it.  Also, it moves the
+buffer to the end of the frame's buffer list (@pxref{Buffer List}).
 @item bury
 This means that if @var{window} is not deleted, its buffer is removed
-from @var{window}'s list of previous buffers.  Also, it moves the buffer
-to the end of the frame's buffer list.  This value provides the most
-reliable remedy to not have @code{switch-to-prev-buffer} switch to this
-buffer again without killing the buffer.
+from @var{window}'s list of previous buffers.  Also, it moves the
+buffer to the end of the frame's buffer list.  This is the most
+reliable way to prevent @code{switch-to-prev-buffer} from switching to
+this buffer again, short of killing the buffer.
 @item kill
 This means to kill @var{window}'s buffer.
 @end table
+The argument @var{bury-or-kill} also specifies what to do with
+@var{window}'s frame when @var{window} should be deleted, if it is the
+only window on its frame, and there are other frames on that frame's
+terminal.  If @var{bury-or-kill} equals @code{kill}, it means to
+delete the frame.  Otherwise, the fate of the frame is determined by
+calling @code{frame-auto-hide-function} (see below) with that frame as
+sole argument.
+This function always sets @var{window}'s @code{quit-restore} parameter
+to @code{nil} unless it deletes the window.
+@end defun
+The window @var{window}'s @code{quit-restore} parameter (@pxref{Window
+Parameters}) should be @code{nil} or a list of four elements:
+@c FIXME: describe what quit-restore-window does if this is nil.
+(@var{method} @var{obuffer} @var{owindow} @var{this-buffer})
+@end lisp
+The first element, @var{method}, is one of the four symbols
+@code{window}, @code{frame}, @code{same} and @code{other}.
+@code{frame} and @code{window} control how to delete @var{window},
+while @code{same} and @code{other} control displaying some other
+buffer in it.
+Specifically, @code{window} means that the window has been specially
+created by @code{display-buffer}; @code{frame} means that a separate
+frame has been created; @code{same}, that the window has only ever
+displayed this buffer; @code{other}, that the window showed another
+buffer before.
+The second element, @var{obuffer}, is either one of the symbols
+@code{window} or @code{frame}, or a list of the form
+(@var{prev-buffer} @var{prev-window-start} @var{prev-window-point} 
+@end lisp
+which says which buffer was shown in @var{window} before, that
+buffer's window start (@pxref{Window Start and End}) and window point
+(@pxref{Window Point}) positions at that time, and
+@var{window}'s height at that time.  If @var{prev-buffer} is still
+live when quitting @var{window}, quitting the window may reuse
+@var{window} to display @var{prev-buffer}.
+The third element, @var{owindow}, is the window that was selected
+just before the displaying was done.  If quitting deletes
+@var{window}, it tries to select @var{owindow}.
+The fourth element, @var{this-buffer}, is the buffer whose displaying
+set the @code{quit-restore} parameter.  Quitting @var{window} may delete
+that window only if it still shows that buffer.
+Quitting @var{window} tries to delete it if and only if (1)
+@var{method} is either @code{window} or @code{frame}, (2) the window
+has no history of previously-displayed buffers and (3)
+@var{this-buffer} equals the buffer currently displayed in
+@var{window}.  If @var{window} is part of an atomic window
+(@pxref{Atomic Windows}), quitting will try to delete the root of that
+atomic window instead.  In either case, it tries to avoid signaling an
+error when @var{window} cannot be deleted.
+If @var{obuffer} is a list, and @var{prev-buffer} is still live,
+quitting displays @var{prev-buffer} in @var{window} according to the
+rest of the elements of @var{obuffer}.  This includes resizing the
+window to @var{height} if it was temporarily resized to display
+Otherwise, if @var{window} was previously used for displaying other
+buffers (@pxref{Window History}), the most recent buffer in that
+history will be displayed.
+@c FIXME: Should we document display-buffer-reuse-window?
+If we document display-buffer-record-window, it should be with @defun.
+And maybe not here.
 Typically, the display routines run by @code{display-buffer} will set
-the @code{quit-restore} window parameter correctly.  It's also
-possible to set it manually, using the following code for displaying
-@var{buffer} in @var{window}:
+the @code{quit-restore} window parameter correctly.  You can also set
+it manually, using the following code for displaying @var{buffer} in
@@ -4361,11 +4393,10 @@ possible to set it manually, using the following code 
for displaying
 Setting the window history to @code{nil} ensures that a future call to
 @code{quit-window} can delete the window altogether.
+@end ignore
-@end defun
-The following option specifies how to deal with a frame containing just
-one window that should be either quit, or whose buffer should be buried.
+The following option specifies a function to do the right thing with a
+frame containing one window when quitting that window.
 @defopt frame-auto-hide-function
 The function specified by this option is called to automatically hide
@@ -4394,7 +4425,6 @@ that frame's @code{auto-hide-function} frame parameter 
 Interaction Parameters}).
 @end defopt
 @node Side Windows
 @section Side Windows
 @cindex side windows
diff --git a/etc/NEWS b/etc/NEWS
index b55b306..8d83b2a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -163,6 +163,12 @@ the previous definition to be discarded, which was 
probably not
 intended when this occurs in batch mode.  To remedy the error, rename
 tests so that they all have unique names.
+*** ERT can generate JUnit test reports.
+When environment variable 'EMACS_TEST_JUNIT_REPORT' is set, ERT
+generates a JUnit test report under this file name.  This is useful
+for Emacs integration into CI/CD test environments.
 ** Emoji
@@ -1143,6 +1149,7 @@ This variable is bound to t during the preparation of a 
"*Help*" buffer.
 ** 'date-to-time' now assumes earliest values if its argument lacks
 month, day, or time.  For example, (date-to-time "2021-12-04") now
 assumes a time of 00:00 instead of signaling an error.
 * Changes in Emacs 29.1 on Non-Free Operating Systems
diff --git a/etc/NEWS.28 b/etc/NEWS.28
index eb65213..d2565e5 100644
--- a/etc/NEWS.28
+++ b/etc/NEWS.28
@@ -1588,9 +1588,9 @@ and the result is not truncated in any way.
 It no longer has lower precedence than '+' and '-'.
-*** Calc now marks its windows dedicated.
-The new user option 'calc-make-windows-dedicated' controls this.  It
-is t by default; set to nil to get back the old behavior.
+*** New user option 'calc-make-windows-dedicated'.
+When this user option is non-nil, Calc will mark its windows as
 ** Calendar
diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index 9774ddf..d426e28 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -1423,7 +1423,7 @@ commands given here will actually operate on the 
*Calculator* stack."
     (require 'calc-ext)
     (calc-set-language calc-language calc-language-option t)))
-(defcustom calc-make-windows-dedicated t
+(defcustom calc-make-windows-dedicated nil
   "If non-nil, windows displaying Calc buffers will be marked dedicated.
 See `window-dedicated-p' for what that means."
   :version "28.1"
diff --git a/lisp/completion.el b/lisp/completion.el
index 643f2da..a77cccd 100644
--- a/lisp/completion.el
+++ b/lisp/completion.el
@@ -492,7 +492,7 @@ Used to decide whether to save completions.")
 ;; Old name, non-namespace-clean.
-(defvaralias 'cmpl-syntax-table 'completion-syntax-table)
+(define-obsolete-variable-alias 'cmpl-syntax-table 'completion-syntax-table 
 (defvar-local completion-syntax-table completion-standard-syntax-table
   "This variable holds the current completion syntax table.")
@@ -2220,7 +2220,7 @@ TYPE is the type of the wrapper to be added.  Can be 
:before or :under."
 (completion-def-wrapper 'delete-backward-char-untabify :backward)
 ;; Old name, non-namespace-clean.
-(defalias 'initialize-completions #'completion-initialize)
+(define-obsolete-function-alias 'initialize-completions 
#'completion-initialize "29.1")
 (provide 'completion)
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index 946193e..981e239 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -65,6 +65,8 @@
 (require 'pp)
 (require 'map)
+(autoload 'xml-escape-string "xml.el")
 ;;; UI customization options.
 (defgroup ert ()
@@ -247,7 +249,6 @@ in batch mode, an error is signalled.
   "The regexp the `find-function' mechanisms use for finding test 
 (define-error 'ert-test-failed "Test failed")
 (define-error 'ert-test-skipped "Test skipped")
@@ -677,7 +678,6 @@ and is displayed in front of the value of MESSAGE-FORM."
 ;;; Facilities for running a single test.
 (defvar ert-debug-on-error nil
@@ -1437,7 +1437,9 @@ Returns the stats object."
                                   (if (getenv "EMACS_TEST_VERBOSE")
                                       (ert-reason-for-test-result result)
-              (message "%s" "")))))
+              (message "%s" ""))
+            (when (getenv "EMACS_TEST_JUNIT_REPORT")
+              (ert-write-junit-test-report stats)))))
         (cl-destructuring-bind (stats test result) event-args
@@ -1525,6 +1527,128 @@ the tests)."
       (kill-emacs 2))))
+(defun ert-write-junit-test-report (stats)
+  "Write a JUnit test report, generated from STATS."
+  ;; 
+  ;; https://llg.cubic.org/docs/junit/
+  (unless (zerop (length (ert--stats-tests stats)))
+    (when-let ((test-file
+                (symbol-file
+                 (ert-test-name (aref (ert--stats-tests stats) 0)) 
+      (with-temp-file (file-name-with-extension test-file "xml")
+        (insert "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
+        (insert (format "<testsuites name=\"%s\" tests=\"%s\" failures=\"%s\" 
skipped=\"%s\" time=\"%s\">\n"
+                        (file-name-nondirectory test-file)
+                        (ert-stats-total stats)
+                        (ert-stats-completed-unexpected stats)
+                        (ert-stats-skipped stats)
+                        (float-time
+                         (time-subtract
+                          (ert--stats-end-time stats)
+                          (ert--stats-start-time stats)))))
+        (insert (format "  <testsuite id=\"0\" name=\"%s\" tests=\"%s\" 
failures=\"%s\" skipped=\"%s\" time=\"%s\" timestamp=\"%s\">\n"
+                        (file-name-nondirectory test-file)
+                        (ert-stats-total stats)
+                        (ert-stats-completed-unexpected stats)
+                        (ert-stats-skipped stats)
+                        (float-time
+                         (time-subtract
+                          (ert--stats-end-time stats)
+                          (ert--stats-start-time stats)))
+                        (ert--format-time-iso8601 (ert--stats-end-time 
+        (insert "    <properties>\n"
+                (format "      <property name=\"selector\" value=\"%s\"/>\n"
+                        (ert--stats-selector stats))
+                "    </properties>\n")
+        (cl-loop for test across (ert--stats-tests stats)
+                 for result = (ert-test-most-recent-result test) do
+                 (insert (format "    <testcase name=\"%s\" status=\"%s\" 
+                                 (xml-escape-string
+                                  (symbol-name (ert-test-name test)))
+                                 (ert-string-for-test-result
+                                  result
+                                  (ert-test-result-expected-p test result))
+                                 (ert-test-result-duration result)))
+                 (if (and (ert-test-result-expected-p test result)
+                          (not (ert-test-skipped-p result))
+                          (zerop (length (ert-test-result-messages result))))
+                     (insert "/>\n")
+                   (insert ">\n")
+                   (if (ert-test-skipped-p result)
+                       (insert (format "      <skipped message=\"%s\" 
+                                       (xml-escape-string
+                                        (string-trim
+                                         (ert-reason-for-test-result result)))
+                                       (ert-string-for-test-result
+                                        result
+                                        (ert-test-result-expected-p
+                                         test result)))
+                               (xml-escape-string
+                                (string-trim
+                                 (ert-reason-for-test-result result)))
+                               "\n"
+                               "      </skipped>\n")
+                     (unless
+                         (ert-test-result-type-p
+                          result (ert-test-expected-result-type test))
+                       (insert (format "      <failure message=\"%s\" 
+                                       (xml-escape-string
+                                        (string-trim
+                                         (ert-reason-for-test-result result)))
+                                       (ert-string-for-test-result
+                                        result
+                                        (ert-test-result-expected-p
+                                         test result)))
+                               (xml-escape-string
+                                (string-trim
+                                 (ert-reason-for-test-result result)))
+                               "\n"
+                               "      </failure>\n")))
+                   (unless (zerop (length (ert-test-result-messages result)))
+                     (insert "      <system-out>\n"
+                             (xml-escape-string
+                              (ert-test-result-messages result))
+                             "      </system-out>\n"))
+                   (insert "    </testcase>\n")))
+        (insert "  </testsuite>\n")
+        (insert "</testsuites>\n")))))
+(defun ert-write-junit-test-summary-report (&rest logfiles)
+  "Write a JUnit summary test report, generated from LOGFILES."
+  (let ((report (file-name-with-extension
+                 (getenv "EMACS_TEST_JUNIT_REPORT") "xml"))
+        (tests 0) (failures 0) (skipped 0) (time 0) (id 0))
+    (with-temp-file report
+      (dolist (logfile logfiles)
+        (let ((test-file (file-name-with-extension logfile "xml")))
+          (when (file-readable-p test-file)
+            (insert-file-contents-literally test-file)
+            (when (looking-at-p
+                   (regexp-quote "<?xml version=\"1.0\" encoding=\"utf-8\"?>"))
+              (delete-region (point) (line-beginning-position 2)))
+            (when (looking-at
+                   "<testsuites name=\".+\" tests=\"\\(.+\\)\" 
failures=\"\\(.+\\)\" skipped=\"\\(.+\\)\" time=\"\\(.+\\)\">")
+              (cl-incf tests (string-to-number (match-string 1)))
+              (cl-incf failures  (string-to-number (match-string 2)))
+              (cl-incf skipped (string-to-number (match-string 3)))
+              (cl-incf time (string-to-number (match-string 4)))
+              (delete-region (point) (line-beginning-position 2)))
+            (when (looking-at "  <testsuite id=\"\\(0\\)\"")
+              (replace-match (number-to-string id) nil nil nil 1)
+              (cl-incf id 1))
+            (goto-char (point-max))
+            (beginning-of-line 0)
+            (when (looking-at-p "</testsuites>")
+              (delete-region (point) (line-beginning-position 2)))
+            (narrow-to-region (point-max) (point-max)))))
+      (insert "</testsuites>\n")
+      (widen)
+      (goto-char (point-min))
+      (insert "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
+      (insert (format "<testsuites name=\"%s\" tests=\"%s\" failures=\"%s\" 
skipped=\"%s\" time=\"%s\">\n"
+                      (file-name-nondirectory report)
+                      tests failures skipped time)))))
 (defun ert-summarize-tests-batch-and-exit (&optional high)
   "Summarize the results of testing.
@@ -1540,6 +1664,8 @@ If HIGH is a natural number, the HIGH long lasting tests 
are summarized."
   ;; behavior.
   (setq attempt-stack-overflow-recovery nil
         attempt-orderly-shutdown-on-fatal-signal nil)
+  (when (getenv "EMACS_TEST_JUNIT_REPORT")
+    (apply #'ert-write-junit-test-summary-report command-line-args-left))
   (let ((nlogs (length command-line-args-left))
         (ntests 0) (nrun 0) (nexpected 0) (nunexpected 0) (nskipped 0)
         nnotrun logfile notests badtests unexpected skipped tests)
@@ -1855,7 +1981,6 @@ Also sets `ert--results-progress-bar-button-begin'."
      ;; should test it again.)
 (defvar ert-test-run-redisplay-interval-secs .1
   "How many seconds ERT should wait between redisplays while running tests.
@@ -2037,7 +2162,6 @@ STATS is the stats object; LISTENER is the results 
           (goto-char (1- (point-max)))
 (defvar ert--selector-history nil
   "List of recent test selectors read from terminal.")
diff --git a/lisp/emacs-lisp/generator.el b/lisp/emacs-lisp/generator.el
index cb02410..ac14127 100644
--- a/lisp/emacs-lisp/generator.el
+++ b/lisp/emacs-lisp/generator.el
@@ -143,8 +143,7 @@ the CPS state machinery."
          (setf ,static-var ,dynamic-var)))))
 (defmacro cps--with-dynamic-binding (dynamic-var static-var &rest body)
-  "Evaluate BODY such that generated atomic evaluations run with
+  "Run BODY's atomic evaluations run with DYNAMIC-VAR bound to STATIC-VAR."
   (declare (indent 2))
        (cps--make-dynamic-binding-wrapper ,dynamic-var ,static-var)
@@ -645,12 +644,11 @@ modified copy."
                          (iter-close iterator)))))
-(defun iter-yield (value)
+(defun iter-yield (_value)
   "When used inside a generator, yield control to caller.
 The caller of `iter-next' receives VALUE, and the next call to
 `iter-next' resumes execution with the form immediately following this
 `iter-yield' call."
-  (identity value)
   (error "`iter-yield' used outside a generator"))
 (defmacro iter-yield-from (value)
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index a2464ad..213b7ab 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -945,12 +945,12 @@ at the moment are:
       ;; In that case, unwrap the value before checking the delimiter
       ;; value.
       (if (and val
-               (not (processp val))
+               (not (eshell-processp val))
                (not (eq val t)))
           (error "Unmatched delimiter: %S" val)
         ;; Eshell-command expect a list like (<process>) to know if the
         ;; command should be async or not.
-        (or (and (processp val) delim) val)))))
+        (or (and (eshell-processp val) delim) val)))))
 (defun eshell-resume-command (proc status)
   "Resume the current command when a process ends."
diff --git a/lisp/help-macro.el b/lisp/help-macro.el
index cd1b51e..ecc7eba 100644
--- a/lisp/help-macro.el
+++ b/lisp/help-macro.el
@@ -167,14 +167,18 @@ and then returns."
                    (let ((cursor-in-echo-area t)
                          (overriding-local-map local-map))
                      (setq key (read-key-sequence
-                                (format "Type one of the options listed%s: "
+                                (format "Type one of listed options%s: "
                                         (if (pos-visible-in-window-p
                                           (concat  ", or "
(help--key-description-fontified (kbd "<PageDown>"))
-                                                   " or "
+                                                   "/"
(help--key-description-fontified (kbd "<PageUp>"))
+                                                   "/"
(help--key-description-fontified (kbd "SPC"))
+                                                   "/"
(help--key-description-fontified (kbd "DEL"))
                                                    " to scroll"))))
                            char (aref key 0)))
diff --git a/lisp/ielm.el b/lisp/ielm.el
index 39820a8..ec7f010 100644
--- a/lisp/ielm.el
+++ b/lisp/ielm.el
@@ -148,28 +148,28 @@ such as `edebug-defun' to work with such inputs."
 This variable is buffer-local.")
 (defvar ielm-header
-  "*** Welcome to IELM ***  Type (describe-mode) for help.\n"
+  (substitute-command-keys
+   "*** Welcome to IELM ***  Type (describe-mode) or press \
+\\[describe-mode] for help.\n")
   "Message to display when IELM is started.")
 (defvaralias 'inferior-emacs-lisp-mode-map 'ielm-map)
-(defvar ielm-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map "\t" 'ielm-tab)
-    (define-key map "\C-m" 'ielm-return)
-    (define-key map "\e\C-m" 'ielm-return-for-effect)
-    (define-key map "\C-j" 'ielm-send-input)
-    (define-key map "\e\C-x" 'eval-defun)         ; for consistency with
-    (define-key map "\e\t" 'completion-at-point)  ; lisp-interaction-mode
-    ;; These bindings are from `lisp-mode-shared-map' -- can you inherit
-    ;; from more than one keymap??
-    (define-key map "\e\C-q" 'indent-sexp)
-    (define-key map "\177" 'backward-delete-char-untabify)
-    ;; Some convenience bindings for setting the working buffer
-    (define-key map "\C-c\C-b" 'ielm-change-working-buffer)
-    (define-key map "\C-c\C-f" 'ielm-display-working-buffer)
-    (define-key map "\C-c\C-v" 'ielm-print-working-buffer)
-    map)
-  "Keymap for IELM mode.")
+(defvar-keymap ielm-map
+  :doc "Keymap for IELM mode."
+  "TAB"     #'ielm-tab
+  "RET"     #'ielm-return
+  "M-RET"   #'ielm-return-for-effect
+  "C-j"     #'ielm-send-input
+  "C-M-x"   #'eval-defun                ; for consistency with
+  "M-TAB"   #'completion-at-point       ; lisp-interaction-mode
+  ;; These bindings are from `lisp-mode-shared-map' -- can you inherit
+  ;; from more than one keymap??
+  "C-M-q"   #'indent-sexp
+  "DEL"     #'backward-delete-char-untabify
+  ;; Some convenience bindings for setting the working buffer
+  "C-c C-b" #'ielm-change-working-buffer
+  "C-c C-f" #'ielm-display-working-buffer
+  "C-c C-v" #'ielm-print-working-buffer)
 (easy-menu-define ielm-menu ielm-map
   "IELM mode menu."
diff --git a/lisp/international/robin.el b/lisp/international/robin.el
index c38cd82..4c498d7 100644
--- a/lisp/international/robin.el
+++ b/lisp/international/robin.el
@@ -529,10 +529,10 @@ Use the longest match method to select a rule."
       (insert (cadr tree))
       (delete-char (- end begin)))))
-;; for backward compatibility
-(fset 'robin-transliterate-region 'robin-convert-region)
-(fset 'robin-transliterate-buffer 'robin-convert-buffer)
+(define-obsolete-function-alias 'robin-transliterate-region
+  #'robin-convert-region "29.1")
+(define-obsolete-function-alias 'robin-transliterate-buffer
+  #'robin-convert-buffer "29.1")
 ;;; Reverse conversion
diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el
index 64acc41..1636e21 100644
--- a/lisp/pcomplete.el
+++ b/lisp/pcomplete.el
@@ -680,8 +680,8 @@ user actually typed in."
        (match-string which arg)
       (throw 'pcompleted nil))))
-(defalias 'pcomplete-match-beginning 'match-beginning)
-(defalias 'pcomplete-match-end 'match-end)
+(define-obsolete-function-alias 'pcomplete-match-beginning #'match-beginning 
+(define-obsolete-function-alias 'pcomplete-match-end #'match-end "29.1")
 (defsubst pcomplete--test (pred arg)
   "Perform a programmable completion predicate match."
@@ -1006,7 +1006,7 @@ Arguments NO-GANGING and ARGS-FOLLOW are currently 
                             ((eq arg-char ?*) (pcomplete-executables))
                             ((eq arg-char ??) nil)
                             ((eq arg-char ?.) (pcomplete-entries))
-                            ((eq arg-char ?\() (eval result))))))
+                            ((eq arg-char ?\() (eval result t))))))
            (setq index (1+ index))))))))
 (defun pcomplete--here (&optional form stub paring form-only)
@@ -1040,7 +1040,7 @@ See the documentation for `pcomplete-here'."
                (funcall form)
              ;; Old calling convention, might still be used by files
              ;; byte-compiled with the older code.
-             (eval form)))))
+             (eval form t)))))
 (defmacro pcomplete-here* (&optional form stub form-only)
@@ -1062,9 +1062,9 @@ See the documentation for `pcomplete-here'."
        pcomplete-window-restore-timer nil))
 (define-obsolete-function-alias 'pcomplete-event-matches-key-specifier-p
-  'eq "27.1")
+  #'eq "27.1")
-(define-obsolete-function-alias 'pcomplete-read-event 'read-event "27.1")
+(define-obsolete-function-alias 'pcomplete-read-event #'read-event "27.1")
 (defun pcomplete-show-completions (completions)
   "List in help buffer sorted COMPLETIONS.
@@ -1244,7 +1244,7 @@ If specific documentation can't be given, be generic."
                    (fboundp 'Info-goto-node))
               (listp pcomplete-help)))
       (if (listp pcomplete-help)
-         (message "%s" (eval pcomplete-help))
+         (message "%s" (eval pcomplete-help t))
        (save-window-excursion (info))
        (declare-function Info-goto-node
                          "info" (nodename &optional fork strict-case))
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 47d8d1c..b403de8 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -2996,8 +2996,9 @@ killed."
                   (mapconcat #'identity args " ")))
             (with-current-buffer buffer
-            (when show (display-buffer buffer))
             (and internal (set-process-query-on-exit-flag process nil))))
+        (when show
+          (pop-to-buffer proc-buffer-name))
@@ -3029,7 +3030,6 @@ process buffer for a list of commands.)"
           (or cmd (python-shell-calculate-command))
           (python-shell-get-process-name dedicated) show)))
-    (set-buffer buffer)
     (get-buffer-process buffer)))
 (defun run-python-internal ()
diff --git a/lisp/progmodes/xscheme.el b/lisp/progmodes/xscheme.el
index 26ffe33..e7667eb 100644
--- a/lisp/progmodes/xscheme.el
+++ b/lisp/progmodes/xscheme.el
@@ -574,9 +574,8 @@ See also the commands \\[xscheme-yank-pop] and 
   (if (consp arg)
-;; Old name, to avoid errors in users' init files.
-(fset 'xscheme-yank-previous-send
-      'xscheme-yank)
+(define-obsolete-function-alias 'xscheme-yank-previous-send
+  #'xscheme-yank "29.1")
 (defun xscheme-yank-pop (arg)
   "Insert or replace a just-yanked expression with an older expression.
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 7a5221d..07aa0f2 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -1178,7 +1178,7 @@ which means the last tab on the tab bar.  For example, 
`C-u 2
 <MODIFIER>-9' selects the tab before the last tab."
   (interactive "p")
   (tab-bar-select-tab (- (length (funcall tab-bar-tabs-function))
-                         (1- (or arg 1)))))
+                         (1- (abs (or arg 1))))))
 (defun tab-bar-switch-to-recent-tab (&optional arg)
   "Switch to ARGth most recently visited tab.
diff --git a/make-dist b/make-dist
index eb04015..db7a74b 100755
--- a/make-dist
+++ b/make-dist
@@ -299,13 +299,6 @@ if [ $check = yes ]; then
     echo "${bogosities}"
-  ## This exits with non-zero status if any .info files need
-  ## rebuilding.
-  if [ -r Makefile ] && [ "$with_info" = "yes" ]; then
-      echo "Checking to see if info files are up-to-date..."
-      make --question info || error=yes
-  fi
   ## Is this a release?
   case $version in
@@ -392,9 +385,11 @@ manifest=MANIFEST
 # other way when adding or deleting a distributed file while not using Git.
 # TODO: maybe this should ignore $update, and always update MANIFEST
 # if .git is present.
+# Filter out the files in msdos/autogen/, as they aren't useful in the
+# tarball, and get in the way during the build of the MSDOS port.
 if ( [ $update = yes ] || [ ! -f $manifest ] ) && [ -r .git ]; then
   echo "Updating $manifest"
-  git ls-files > $manifest || exit
+  git ls-files | sed -e '/^msdos\/autogen\//d' > $manifest || exit
   printf '%s\n' $possibly_non_vc_files $info_files >>$manifest || exit
   sort -u -o $manifest $manifest || exit
diff --git a/src/bignum.c b/src/bignum.c
index 1ac75c1..5c587fc 100644
--- a/src/bignum.c
+++ b/src/bignum.c
@@ -53,6 +53,15 @@ init_bignum (void)
   eassert (mp_bits_per_limb == GMP_NUMB_BITS);
   integer_width = 1 << 16;
+  /* FIXME: The Info node `(gmp) Custom Allocation' states: "No error
+     return is allowed from any of these functions, if they return
+     then they must have performed the specified operation. [...]
+     There's currently no defined way for the allocation functions to
+     recover from an error such as out of memory, they must terminate
+     program execution.  A 'longjmp' or throwing a C++ exception will
+     have undefined results."  But xmalloc and xrealloc do call
+     'longjmp'.  */
   mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp);
   for (int i = 0; i < ARRAYELTS (mpz); i++)
diff --git a/src/sqlite.c b/src/sqlite.c
index 4968ce3..428b84b 100644
--- a/src/sqlite.c
+++ b/src/sqlite.c
@@ -247,7 +247,7 @@ If FILE is nil, an in-memory database will be opened 
instead.  */)
   if (!NILP (file))
       CHECK_STRING (file);
-      file = encode_string (Fexpand_file_name (file, Qnil));
+      file = ENCODE_FILE (Fexpand_file_name (file, Qnil));
       name = xstrdup (SSDATA (file));
@@ -591,16 +591,42 @@ DEFUN ("sqlite-load-extension", Fsqlite_load_extension,
        doc: /* Load an SQlite MODULE into DB.
 MODULE should be the name of an SQlite module's file, a
 shared library in the system-dependent format and having a
-system-dependent file-name extension.  */)
+system-dependent file-name extension.
+Only modules on Emacs' list of allowed modules can be loaded.  */)
   (Lisp_Object db, Lisp_Object module)
   check_sqlite (db, false);
   CHECK_STRING (module);
-  Lisp_Object module_encoded = encode_string (Fexpand_file_name (module, 
-  sqlite3 *sdb = XSQLITE (db)->db;
-  int result = sqlite3_load_extension (sdb, SSDATA (module_encoded),
-                                      NULL, NULL);
+  /* Add names of useful and free modules here.  */
+  const char *allowlist[3] = { "pcre", "csvtable", NULL };
+  char *name = SSDATA (Ffile_name_nondirectory (module));
+  /* Possibly skip past a common prefix.  */
+  const char *prefix = "libsqlite3_mod_";
+  if (!strncmp (name, prefix, strlen (prefix)))
+    name += strlen (prefix);
+  bool do_allow = false;
+  for (const char **allow = allowlist; *allow; allow++)
+    {
+      if (strlen (*allow) < strlen (name)
+         && !strncmp (*allow, name, strlen (*allow))
+         && (!strcmp (name + strlen (*allow), ".so")
+             || !strcmp (name + strlen (*allow), ".DLL")))
+       {
+         do_allow = true;
+         break;
+       }
+    }
+  if (!do_allow)
+    xsignal (Qerror, build_string ("Module name not on allowlist"));
+  int result = sqlite3_load_extension
+                      (XSQLITE (db)->db,
+                       SSDATA (ENCODE_FILE (Fexpand_file_name (module, Qnil))),
+                       NULL, NULL);
   if (result ==  SQLITE_OK)
     return Qt;
   return Qnil;
diff --git a/src/xdisp.c b/src/xdisp.c
index 96c4347..2d45a8d 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -10423,11 +10423,12 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int 
to_x, int to_y, int to_vpos
 /* Move iterator IT backward by a specified y-distance DY, DY >= 0.
-   If DY > 0, move IT backward at least that many pixels.  DY = 0
-   means move IT backward to the preceding line start or BEGV.  This
-   function may move over more than DY pixels if IT->current_y - DY
-   ends up in the middle of a line; in this case IT->current_y will be
-   set to the top of the line moved to.  */
+   If DY > 0, move IT backward that many pixels.
+   DY = 0 means move IT backward to the preceding line start or to BEGV.
+   This function may move over less or more than DY pixels if
+   IT->current_y - DY ends up in the middle of a line; in this case
+   IT->current_y will be set to the top of the line either before or
+   after the exact pixel coordinate.  */
 move_it_vertically_backward (struct it *it, int dy)
diff --git a/test/Makefile.in b/test/Makefile.in
index f2c4958..eeda291 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -353,6 +353,7 @@ mostlyclean:
        find . '(' -name '*.log' -o -name '*.log~' ')' $(FIND_DELETE)
+       find . '(' -name '*.xml' -a ! -path '*resources*' ')' $(FIND_DELETE)
        rm -f ${srcdir}/lisp/gnus/mml-sec-resources/random_seed
        rm -f $(test_module_dir)/*.o $(test_module_dir)/*.so \
diff --git a/test/README b/test/README
index 4d447c9..2bd84b5 100644
--- a/test/README
+++ b/test/README
@@ -114,6 +114,9 @@ mode--only the names of the failed tests are listed.  If the
 $EMACS_TEST_VERBOSE environment variable is set, the failure summaries
 will also include the data from the failing test.
+If the $EMACS_TEST_JUNIT_REPORT environment variable is set to a file
+name, a JUnit test report is generated under this name.
 Some of the tests require a remote temporary directory
 (autorevert-tests.el, filenotify-tests.el, shadowfile-tests.el and
 tramp-tests.el).  Per default, a mock-up connection method is used
diff --git a/test/infra/Makefile.in b/test/infra/Makefile.in
index fd11d36..e4f9974 100644
--- a/test/infra/Makefile.in
+++ b/test/infra/Makefile.in
@@ -93,10 +93,8 @@ all: generate-test-jobs
 .PHONY: generate-test-jobs $(FILE) $(SUBDIR_TARGETS)
-generate-test-jobs: clean $(FILE) $(SUBDIR_TARGETS)
+generate-test-jobs: $(FILE) $(SUBDIR_TARGETS)
-       @rm -f $(FILE)
+       @echo "# Generated by \"make generate-test-jobs\", don't edit." >$(FILE)
diff --git a/test/infra/gitlab-ci.yml b/test/infra/gitlab-ci.yml
index b0ea681..3903642 100644
--- a/test/infra/gitlab-ci.yml
+++ b/test/infra/gitlab-ci.yml
@@ -44,6 +44,7 @@ workflow:
   GIT_STRATEGY: fetch
+  EMACS_TEST_JUNIT_REPORT: junit-test-report.xml
   # Use TLS 
@@ -85,7 +86,7 @@ default:
     # TODO: with make -j4 several of the tests were failing, for
     # example shadowfile-tests, but passed without it.
     - 'export PWD=$(pwd)'
-    - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} -e 
EMACS_TEST_VERBOSE=${EMACS_TEST_VERBOSE} --volumes-from $(docker ps -q -f 
"label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name ${test_name} 
${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git fetch ${PWD} HEAD 
&& echo checking out these updated files && git diff --name-only FETCH_HEAD && 
( git diff --name-only FETCH_HEAD | xargs git checkout -f FETCH_HEAD ) && make 
- [...]
+    - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} -e 
EMACS_TEST_VERBOSE=${EMACS_TEST_VERBOSE} --volumes-from $(docker ps -q -f 
"label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name ${test_name} 
${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git fetch ${PWD} HEAD 
&& echo checking out these updated files && git diff --name-only FETCH_HEAD && 
( git diff --name-only FET [...]
     # - docker ps -a
     # - printenv
@@ -93,7 +94,8 @@ default:
     # Prepare test artifacts.
     - test -n "$(docker ps -aq -f name=${test_name})" && docker cp 
${test_name}:checkout/test ${test_name}
     - test -n "$(docker ps -aq -f name=${test_name})" && docker rm ${test_name}
-    - find ${test_name} ! -name "*.log" -type f -delete
+    - find ${test_name} ! \( -name "*.log" -o -name ${EMACS_TEST_JUNIT_REPORT} 
\) -type f -delete
+    # BusyBox find does not know -empty.
     - find ${test_name} -type d -depth -exec rmdir {} + 2>/dev/null
@@ -103,7 +105,6 @@ default:
       when: always
     - changes:
         - "**.in"
-        - "**.yml"
         - GNUmakefile
         - aclocal.m4
         - autogen.sh
@@ -112,7 +113,7 @@ default:
         - lib/malloc/*.{h,c}
         - lisp/emacs-lisp/*.el
         - src/*.{h,c}
-        - test/infra/Dockerfile.emba
+        - test/infra/*
     - changes:
         # gfilemonitor, kqueue
         - src/gfilenotify.c
@@ -133,9 +134,11 @@ default:
     name: ${test_name}
     public: true
     expire_in: 1 week
+    when: always
       - ${test_name}/
-    when: always
+    reports:
+      junit: ${test_name}/${EMACS_TEST_JUNIT_REPORT}
@@ -143,12 +146,11 @@ default:
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
         - "**.in"
-        - "**.yml"
         - src/ns*.{h,m}
         - src/macfont.{h,m}
         - lisp/term/ns-win.el
         - nextstep/**
-        - test/infra/Dockerfile.emba
+        - test/infra/*
@@ -156,12 +158,11 @@ default:
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
         - "**.in"
-        - "**.yml"
         - lisp/autorevert.el
         - lisp/filenotify.el
         - lisp/net/tramp-sh.el
         - src/gfilenotify.c
-        - test/infra/Dockerfile.emba
+        - test/infra/*
         - test/lisp/autorevert-tests.el
         - test/lisp/filenotify-tests.el
@@ -171,11 +172,10 @@ default:
     - if: '$CI_PIPELINE_SOURCE == "schedule"'
         - "**.in"
-        - "**.yml"
         - lisp/emacs-lisp/comp.el
         - lisp/emacs-lisp/comp-cstr.el
         - src/comp.{h,m}
-        - test/infra/Dockerfile.emba
+        - test/infra/*
         - test/src/comp-resources/*.el
         - test/src/comp-tests.el
   timeout: 8 hours
diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml
index bad8575..63b052b 100644
--- a/test/infra/test-jobs.yml
+++ b/test/infra/test-jobs.yml
@@ -1,3 +1,4 @@
+# Generated by "make generate-test-jobs", don't edit.
   stage: normal
diff --git a/test/lisp/progmodes/python-tests.el 
index 15bda5c..2d1ccdc 100644
--- a/test/lisp/progmodes/python-tests.el
+++ b/test/lisp/progmodes/python-tests.el
@@ -5449,15 +5449,21 @@ buffer with overlapping strings."
     (should (eolp))))
-;; After call `run-python' the buffer running the python process is current.
-(ert-deftest python-tests--bug31398 ()
-  "Test for https://debbugs.gnu.org/31398 ."
+;; Interactively, `run-python' focuses the buffer running the
+;; interpreter.
+(ert-deftest python-tests--run-python-selects-window ()
+  "Test for bug#31398.  See also bug#44421 and bug#52380."
   (skip-unless (executable-find python-tests-shell-interpreter))
-  (let ((buffer (process-buffer (run-python nil nil 'show))))
-    (should (eq buffer (current-buffer)))
+  (let* ((buffer (process-buffer (run-python nil nil 'show)))
+         (window (get-buffer-window buffer)))
+    ;; We look at `selected-window' rather than `current-buffer'
+    ;; because as `(elisp)Current buffer' says, the latter will only
+    ;; be synchronized with the former when returning to the "command
+    ;; loop"; until then, `current-buffer' can change arbitrarily.
+    (should (eq window (selected-window)))
     (pop-to-buffer (other-buffer))
     (run-python nil nil 'show)
-    (should (eq buffer (current-buffer)))))
+    (should (eq window (selected-window)))))
 (ert-deftest python-tests--fill-long-first-line ()
diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el
index 6a88f0f..d1076e4 100644
--- a/test/src/sqlite-tests.el
+++ b/test/src/sqlite-tests.el
@@ -182,4 +182,36 @@
     (sqlite-close db)
     (should-error (sqlite-select db "select * from test6"))))
+(ert-deftest sqlite-load-extension ()
+  (skip-unless (sqlite-available-p))
+  (let (db)
+    (setq db (sqlite-open))
+    (should-error
+     (sqlite-load-extension db "/usr/lib/sqlite3/notpcre.so"))
+    (should-error
+     (sqlite-load-extension db "/usr/lib/sqlite3/n"))
+    (should-error
+     (sqlite-load-extension db "/usr/lib/sqlite3/"))
+    (should-error
+     (sqlite-load-extension db "/usr/lib/sqlite3"))
+    (should
+     (memq
+      (sqlite-load-extension db "/usr/lib/sqlite3/pcre.so")
+      '(nil t)))
+    (should-error
+     (sqlite-load-extension
+      db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_notcsvtable.so"))
+    (should-error
+     (sqlite-load-extension
+      db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtablen.so"))
+    (should-error
+     (sqlite-load-extension
+      db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable"))
+    (should
+     (memq
+      (sqlite-load-extension
+       db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable.so")
+      '(nil t)))))
 ;;; sqlite-tests.el ends here

reply via email to

[Prev in Thread] Current Thread [Next in Thread]