diff options
| author | Przemysław Kryger | 2025-09-02 09:28:13 +0100 |
|---|---|---|
| committer | Philip Kaludercic | 2025-12-07 22:27:13 +0100 |
| commit | 3b0dcb0b1b2e88ae3e960bf74588c1a6f13ccd01 (patch) | |
| tree | 9a63efc95192180ffc07728c16a93755bdd5b6ad | |
| parent | dba1c734bfdbc6432c8f6028583491b8c8f9663e (diff) | |
| download | emacs-3b0dcb0b1b2e88ae3e960bf74588c1a6f13ccd01.tar.gz emacs-3b0dcb0b1b2e88ae3e960bf74588c1a6f13ccd01.zip | |
Add tests for package-vc
* test/lisp/package-vc-tests.el
(package-vc-tests-preserve-artefacts): When non nil then
preserve temporary test files and buffers.
(package-vc-tests-dir, package-vc-tests-packages)
(package-vc-tests-repository): Silence byte compiler.
(package-vc-tests-packages): Define packages to test.
(package-vc-tests-add): Copy a an in file template, update
SUFFIX in it and add it to index.
(package-vc-tests-create-repository): Create a package git
repository with a test package's source.
(package-vc-tests-package-desc): Retrieve a `package-desc' for
tested package.
(package-vc-tests-package-spec): Retrieve a pkg-spec for tested
package.
(package-vc-tests-package-lisp-dir): Determine a lisp directory
for a package.
(package-vc-tests-package-main-file): Calculate expected
location of package's main file.
(package-vc-tests-load-history-marker): Create a load history
marker.
(package-vc-tests-load-history-pattern): Create a regexp pattern
to search in `load-history'.
(package-vc-tests-load-history-position): Calculate a position
in `load-history'.
(package-vc-tests-load-history-interesting-entries): Return
`load-history' entries related to the current
`package-vc-tests-dir'.
(package-vc-tests-explain-load-history-position): Return ERT
explanation for load history position failures.
(package-vc-tests-log-buffer-name): Return name of a log buffer
used to build package or its documentation.
(package-vc-tests-log-buffer-exists): Return non-nil when a log
buffer used to build package or its documentation exists.
(package-vc-tests-explain-log-buffer): Print contents of log
buffer used to build package or its documentation and return ERT
explanation for the failure.
(package-vc-tests-elc-files): Check that there are elc files and
that there is no compiled autoloads file amongst them.
(package-vc-tests-assert-delete-elc): Assert that .elc files are
present for a package.
(package-vc-tests-assert-package-alist): Assert that
`package-alist' contains a `package-desc' for package, and that
the `package-desc' has correct slot `version' and slot
`dir'.:(package-vc-tests-reset-head^): Reset head of checkout of
tested packages to HEAD^.
(package-vc-tests-packages-head): Return current checkout
revision.
(package-vc-tests-make-spec): Make a new test spec for a test
package.
(with-package-vc-tests-environment): Setup test environment.
(package-vc-tests-environment-tear-down): Tear down test
environment.
(with-package-vc-tests-installed): Withing a test environment,
install package, evaluate test body, and then tear down the test
environment.
(package-vc-tests-install-from-elpa)
(package-vc-tests-install-from-spec): Install a test package.
(package-vc-tests-checkout-from-elpa-install-from-checkout)
(package-vc-tests-checkout-with-git-install-from-checkout):
Checkout and install a test package.
(package-vc-tests-package-vc-async-wait): Wait for an
asynchronous VC command to finish.
(package-vc-tests-deftest): Define series tests for each package
in `package-vc-tests-under-test'.
(install-post-conditions): Tests that after installing a test
package the `load-history' entries, package's main file, commit,
elc files, and `package-alist' entry are correct.
(require): Test that after calling `require' the `load-history'
entries are correct.
(upgrade, upgrade-all): Test that after calling
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, package's elc files, commit, and `package-alist' entry
are correct.
(upgrade-after-require, upgrade-all-after-require): Test that
after calling `require' followed by
`package-vc-upgrade'/`package-vc-upgrade-all' the `load-history'
entries, commit, package's elc files, and `package-alist' entry
are correct.
(rebuild): Test that after calling `package-vc-rebuild' on an
old version of a package, the package's old function, old macro,
elc files, and `package-alist' entry are correct.
(rebuild-after-require): Test that after calling `require'
followed by `package-vc-rebuild' on an old version of a package,
the package's old function, old macro, elc files, and
`package-alist' entry are correct.
(prepare-patch): Test that after calling
`package-vc-prepare-patch' the message buffer is correct.
(log-incoming): Test that after calling
`package-vc-log-incoming' the log buffer is correct.
(pkg-spec-doc-make-shell-command): Test that :doc, :make, and
:shell-command slots in a pkg spec execute.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in:
Code template of version 0.1 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in:
* test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in:
Code template of code of version 0.2 of a test package.
* test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in:
* test/lisp/package-vc-resources/test-package-SUFFIX.texi.in:
Documentation template of a test package.
* test/lisp/package-vc-resources/Makefile.in: Makefile template of
a test package.
Co-developed-by: Philip Kaludercic <philipk@posteo.net>
(Bug#79188)
8 files changed, 1124 insertions, 0 deletions
diff --git a/test/lisp/package-vc-resources/Makefile.in b/test/lisp/package-vc-resources/Makefile.in new file mode 100644 index 00000000000..8618ae8f2f4 --- /dev/null +++ b/test/lisp/package-vc-resources/Makefile.in | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | .PHONY: build-test-package-SUFFIX | ||
| 2 | |||
| 3 | build-test-package-SUFFIX: | ||
| 4 | @touch test-package-SUFFIX.make-build | ||
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in new file mode 100644 index 00000000000..9e4e38b74a4 --- /dev/null +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-inc.texi.in | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | @c -*- texinfo -*- | ||
| 2 | @chapter Second chapter for test-package-SUFFIX | ||
| 3 | Second test text. | ||
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in new file mode 100644 index 00000000000..c8bfce3e8ab --- /dev/null +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.1.el.in | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | ;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;;; Commentary: | ||
| 4 | ;; | ||
| 5 | ;; Test package SUFFIX library. | ||
| 6 | |||
| 7 | ;;; Code: | ||
| 8 | |||
| 9 | (defmacro test-package-SUFFIX-mac (arg) | ||
| 10 | ;; checkdoc-params: (arg) | ||
| 11 | "Old test macro for `test-package-SUFFIX'." | ||
| 12 | `(format "Old macro %s" ,arg)) | ||
| 13 | |||
| 14 | (provide 'test-package-SUFFIX-lib) | ||
| 15 | |||
| 16 | ;;; test-package-SUFFIX-lib.el ends here | ||
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in new file mode 100644 index 00000000000..bfa4c35f014 --- /dev/null +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-lib-v0.2.el.in | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | ;;; test-package-SUFFIX-lib.el --- Test package lib -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;;; Commentary: | ||
| 4 | ;; | ||
| 5 | ;; Test package SUFFIX library. | ||
| 6 | |||
| 7 | ;;; Code: | ||
| 8 | |||
| 9 | (defmacro test-package-SUFFIX-mac (arg) | ||
| 10 | ;; checkdoc-params: (arg) | ||
| 11 | "Test macro for `test-package-SUFFIX'." | ||
| 12 | `(format "New macro %s" ,arg)) | ||
| 13 | |||
| 14 | (provide 'test-package-SUFFIX-lib) | ||
| 15 | |||
| 16 | ;;; test-package-SUFFIX-lib.el ends here | ||
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in new file mode 100644 index 00000000000..ddecc88e1c5 --- /dev/null +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.1.el.in | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | ;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;; Homepage: https://test-domain.org | ||
| 4 | ;; Maintainer: Test Maintainer <test-maintainer@test-domain.org> | ||
| 5 | ;; Package-Requires: ((emacs "30.1")) | ||
| 6 | ;; Version: 0.1 | ||
| 7 | |||
| 8 | ;;; Commentary: | ||
| 9 | ;; | ||
| 10 | ;; Test package SUFFIX. | ||
| 11 | |||
| 12 | ;;; Code: | ||
| 13 | |||
| 14 | (require 'test-package-SUFFIX-lib) | ||
| 15 | |||
| 16 | ;;;###autoload | ||
| 17 | (defun test-package-SUFFIX-func (arg) | ||
| 18 | ;; checkdoc-params: (arg) | ||
| 19 | "Test function for `test-package-SUFFIX'." | ||
| 20 | (test-package-SUFFIX-mac arg)) | ||
| 21 | |||
| 22 | ;;;###autoload | ||
| 23 | (defun test-package-SUFFIX-old-func () | ||
| 24 | "Old test function for `test-package-SUFFIX'.") | ||
| 25 | |||
| 26 | (provide 'test-package-SUFFIX) | ||
| 27 | |||
| 28 | ;;; test-package-SUFFIX.el ends here | ||
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in new file mode 100644 index 00000000000..902066d787d --- /dev/null +++ b/test/lisp/package-vc-resources/test-package-SUFFIX-v0.2.el.in | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | ;;; test-package-SUFFIX.el --- Test package -*- lexical-binding: t -*- | ||
| 2 | |||
| 3 | ;; Homepage: https://test-domain.org | ||
| 4 | ;; Maintainer: Test Maintainer <test-maintainer@test-domain.org> | ||
| 5 | ;; Package-Requires: ((emacs "30.1")) | ||
| 6 | ;; Version: 0.2 | ||
| 7 | |||
| 8 | ;;; Commentary: | ||
| 9 | ;; | ||
| 10 | ;; Test package SUFFIX. | ||
| 11 | |||
| 12 | ;;; Code: | ||
| 13 | |||
| 14 | (require 'test-package-SUFFIX-lib) | ||
| 15 | |||
| 16 | ;;;###autoload | ||
| 17 | (defun test-package-SUFFIX-func (arg) | ||
| 18 | ;; checkdoc-params: (arg) | ||
| 19 | "Test function for `test-package-SUFFIX'." | ||
| 20 | (test-package-SUFFIX-mac arg)) | ||
| 21 | |||
| 22 | (provide 'test-package-SUFFIX) | ||
| 23 | |||
| 24 | ;;; test-package-SUFFIX.el ends here | ||
diff --git a/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in new file mode 100644 index 00000000000..0fc4fc3653d --- /dev/null +++ b/test/lisp/package-vc-resources/test-package-SUFFIX.texi.in | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | \input texinfo @c -*- texinfo -*- | ||
| 2 | @settitle Info for test-package-SUFFIX | ||
| 3 | @direntry | ||
| 4 | * Test-package-SUFFIX: (test-package-SUFFIX). test-package-SUFFIX. | ||
| 5 | @end direntry | ||
| 6 | |||
| 7 | @chapter First chapter for test-package-SUFFIX | ||
| 8 | First test text. | ||
| 9 | |||
| 10 | @include test-package-SUFFIX-inc.texi | ||
| 11 | @bye | ||
diff --git a/test/lisp/package-vc-tests.el b/test/lisp/package-vc-tests.el new file mode 100644 index 00000000000..74235da7ec5 --- /dev/null +++ b/test/lisp/package-vc-tests.el | |||
| @@ -0,0 +1,1022 @@ | |||
| 1 | ;;; package-vc-tests.el --- Tests for package-vc -*- lexical-binding:t -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2025 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Przemsyław Kryger <pkryger@gmail.com> | ||
| 6 | ;; Maintainer: Philip Kaludercic <philipk@posteo.net> | ||
| 7 | ;; Keywords: package | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 14 | ;; (at your option) any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
| 23 | |||
| 24 | ;;; Commentary: | ||
| 25 | |||
| 26 | ;; These tests focus on verifying post conditions for `package-vc' | ||
| 27 | ;; operations on packages. These tests install and load test packages | ||
| 28 | ;; with a sample test implementation, resulting in modification of | ||
| 29 | ;; numerous global variables, for example `load-history', `load-path', | ||
| 30 | ;; `features', etc. When run with `ert' it may contaminate current | ||
| 31 | ;; Emacs session. For this reason, tests execute their bodies in | ||
| 32 | ;; `with-package-vc-tests-installed' (which see), that takes care of | ||
| 33 | ;; cleaning up the environment. | ||
| 34 | |||
| 35 | ;;; Code: | ||
| 36 | |||
| 37 | (require 'package-vc) | ||
| 38 | (require 'package) | ||
| 39 | (require 'vc-git) | ||
| 40 | (require 'vc) | ||
| 41 | (require 'cl-lib) | ||
| 42 | (require 'info) | ||
| 43 | (require 'ert-x) | ||
| 44 | (require 'ert) | ||
| 45 | |||
| 46 | (defvar package-vc-tests-preserve-artefacts nil | ||
| 47 | "When non-nil preserve temporary files and buffers produced by tests. | ||
| 48 | Each test produces a new temporary directory for each package under | ||
| 49 | test. This leads to creation of [length of `package-vc-tests-packages'] | ||
| 50 | times [number of tests executed] temporary directories for each tests | ||
| 51 | run. Tests create temporary directories with `make-temp-file', which | ||
| 52 | see. | ||
| 53 | |||
| 54 | In addition some tests may produce temporary buffers, for example when | ||
| 55 | building a documentation. | ||
| 56 | |||
| 57 | When this variable is nil then delete temporary directories and kill | ||
| 58 | temporary buffers as soon as they are no longer needed. When this | ||
| 59 | variable is a symbol, then preserve temporary directories and buffers | ||
| 60 | for the package that matches the symbol. When this variable is a list | ||
| 61 | of symbols, then preserve temporary directories and buffers for each | ||
| 62 | package that matches a symbol in the list. When this variable is t then | ||
| 63 | preserve all temporary directories.") | ||
| 64 | |||
| 65 | (defvar package-vc-tests-dir) | ||
| 66 | (defvar package-vc-tests-packages) | ||
| 67 | (defvar package-vc-tests-repository) | ||
| 68 | |||
| 69 | (eval-and-compile | ||
| 70 | (defun package-vc-tests-packages () | ||
| 71 | "Return a list of package definitions to test. | ||
| 72 | When variable `package-vc-tests-packages' is bound then return its | ||
| 73 | value. If `package-vc-tests-dir' is bound then each entry is in a form | ||
| 74 | of (PKG CHECKOUT-DIR LISP-DIR INSTALL-FUN), where PKG is a package | ||
| 75 | name (a symbol), CHECKOUT-DIR is an expected checkout directory, | ||
| 76 | LISP-DIR is a directory with package's sources (relative to | ||
| 77 | CHECKOUT-DIR), and INSTALL-FUN is a function that checkouts and install | ||
| 78 | the package. Otherwise each entry is in a form of PKG." | ||
| 79 | (if (boundp 'package-vc-tests-packages) | ||
| 80 | package-vc-tests-packages | ||
| 81 | (cl-macrolet ((test-package-def | ||
| 82 | (pkg checkout-dir-exp lisp-dir install-fun) | ||
| 83 | `(if (boundp 'package-vc-tests-dir) | ||
| 84 | (list | ||
| 85 | ',pkg | ||
| 86 | (expand-file-name (symbol-name ',pkg) | ||
| 87 | ,checkout-dir-exp) | ||
| 88 | ,lisp-dir | ||
| 89 | #',install-fun) | ||
| 90 | ',pkg))) | ||
| 91 | (list | ||
| 92 | ;; checkout and install with `package-vc-install' (on ELPA) | ||
| 93 | (test-package-def | ||
| 94 | test-package-1 package-user-dir nil | ||
| 95 | package-vc-tests-install-from-elpa) | ||
| 96 | ;; checkout and install with `package-vc-install' (not on ELPA) | ||
| 97 | (test-package-def | ||
| 98 | test-package-2 package-user-dir nil | ||
| 99 | package-vc-tests-install-from-spec) | ||
| 100 | ;; checkout with `package-vc-checktout' and install with | ||
| 101 | ;; `package-vc-install-from-checkout' (on ELPA) | ||
| 102 | (test-package-def | ||
| 103 | test-package-3 package-vc-tests-dir nil | ||
| 104 | package-vc-tests-checkout-from-elpa-install-from-checkout) | ||
| 105 | ;; checkout with git and install with | ||
| 106 | ;; `package-vc-install-from-checkout' | ||
| 107 | (test-package-def | ||
| 108 | test-package-4 package-vc-tests-dir nil | ||
| 109 | package-vc-tests-checkout-with-git-install-from-checkout) | ||
| 110 | ;; sources in "lisp" sub directory, checkout and install with | ||
| 111 | ;; `package-vc-install' (not on ELPA) | ||
| 112 | (test-package-def | ||
| 113 | test-package-5 package-user-dir "lisp" | ||
| 114 | package-vc-tests-install-from-spec) | ||
| 115 | ;; sources in "lisp" sub directory, checkout with git and | ||
| 116 | ;; install with `package-vc-install-from-checkout' | ||
| 117 | (test-package-def | ||
| 118 | test-package-6 package-vc-tests-dir "lisp" | ||
| 119 | package-vc-tests-checkout-with-git-install-from-checkout) | ||
| 120 | ;; sources in "src" sub directory, checkout and install with | ||
| 121 | ;; `package-vc-install' (on ELPA) | ||
| 122 | (test-package-def | ||
| 123 | test-package-7 package-user-dir "src" | ||
| 124 | package-vc-tests-install-from-elpa) | ||
| 125 | ;; sources in "src" sub directory, checkout with | ||
| 126 | ;; `package-vc-checktout' and install with | ||
| 127 | ;; `package-vc-install-from-checkout' (on ELPA) | ||
| 128 | (test-package-def | ||
| 129 | test-package-8 package-vc-tests-dir nil | ||
| 130 | package-vc-tests-checkout-from-elpa-install-from-checkout) | ||
| 131 | ;; sources in "custom-dir" sub directory, checkout and install | ||
| 132 | ;; with `package-vc-install' (on ELPA) | ||
| 133 | (test-package-def | ||
| 134 | test-package-9 package-user-dir "custom-dir" | ||
| 135 | package-vc-tests-install-from-elpa)))))) | ||
| 136 | |||
| 137 | ;; TODO: add test for deleting packages, with asserting | ||
| 138 | ;; `package-vc-selected-packages' | ||
| 139 | |||
| 140 | ;; TODO: clarify `package-vc-install-all' behaviour with regards to | ||
| 141 | ;; packages installed with `package-vc' but not stored in | ||
| 142 | ;; `package-vc-selected-packages' i.e., packages from ELPAs | ||
| 143 | |||
| 144 | (defun package-vc-tests-add (suffix in-file &optional lisp-dir) | ||
| 145 | "Create a new file from IN-FILE template updating SUFFIX in it. | ||
| 146 | When LISP-DIR is non-nil place the NAME file under LISP-DIR." | ||
| 147 | (let* ((resource-dir (ert-resource-directory)) | ||
| 148 | (suffix (if (stringp suffix) suffix (format "%s" suffix))) | ||
| 149 | (file (let ((file (replace-regexp-in-string | ||
| 150 | (rx (or "SUFFIX" | ||
| 151 | (: "-v" digit (* "." (1+ digit))) | ||
| 152 | (: ".in" string-end)) ) | ||
| 153 | (lambda (mat) | ||
| 154 | (if (string= mat "SUFFIX") suffix "")) | ||
| 155 | in-file))) | ||
| 156 | (file-name-concat lisp-dir file)))) | ||
| 157 | (unless (zerop (call-process | ||
| 158 | "sed" (expand-file-name in-file resource-dir) | ||
| 159 | `(:file ,file) nil | ||
| 160 | (format "s/SUFFIX/%s/g" suffix))) | ||
| 161 | (error "Failed to invoke sed on %s" in-file)) | ||
| 162 | (vc-git-command nil 0 nil "add" "."))) | ||
| 163 | |||
| 164 | (defun package-vc-tests-create-repository (suffix &optional lisp-dir) | ||
| 165 | "Create a test package repository with SUFFIX. | ||
| 166 | If LISP-DIR is non-nil place sources of the package in LISP-DIR." | ||
| 167 | (let* ((name (format "test-package-%s" suffix)) | ||
| 168 | (repo-dir (expand-file-name (file-name-concat "repo" name) | ||
| 169 | package-vc-tests-dir))) | ||
| 170 | (make-directory (expand-file-name (or lisp-dir ".") repo-dir) t) | ||
| 171 | (let ((default-directory repo-dir)) | ||
| 172 | (vc-git-command nil 0 nil "init" "-b" "master") | ||
| 173 | (package-vc-tests-add | ||
| 174 | suffix "test-package-SUFFIX-lib-v0.1.el.in" lisp-dir) | ||
| 175 | (package-vc-tests-add | ||
| 176 | suffix "test-package-SUFFIX-v0.1.el.in" lisp-dir) | ||
| 177 | (package-vc-tests-add | ||
| 178 | suffix "test-package-SUFFIX.texi.in" lisp-dir) | ||
| 179 | (package-vc-tests-add | ||
| 180 | suffix "test-package-SUFFIX-inc.texi.in" lisp-dir) | ||
| 181 | ;; Place Makefile in root of the repository | ||
| 182 | (package-vc-tests-add | ||
| 183 | suffix "Makefile.in" nil) | ||
| 184 | (vc-git-command nil 0 nil "commit" "-m" "First commit") | ||
| 185 | (package-vc-tests-add | ||
| 186 | suffix "test-package-SUFFIX-lib-v0.2.el.in" lisp-dir) | ||
| 187 | (package-vc-tests-add | ||
| 188 | suffix "test-package-SUFFIX-v0.2.el.in" lisp-dir) | ||
| 189 | (vc-git-command nil 0 nil "commit" "-m" "Second commit") | ||
| 190 | (list repo-dir (vc-git-working-revision nil))))) | ||
| 191 | |||
| 192 | (defun package-vc-tests-package-desc (pkg &optional installed) | ||
| 193 | "Return descriptor of PKG. | ||
| 194 | When INSTALLED is non-nil the descriptor comes from `package-alist'. | ||
| 195 | Otherwise the descriptor comes from `package-archive-contents'. This | ||
| 196 | is to mimic `package-vc--read-package-desc'." | ||
| 197 | (cadr (assq pkg (if installed package-alist package-archive-contents)))) | ||
| 198 | |||
| 199 | (defun package-vc-tests-package-spec (pkg) | ||
| 200 | "Return pkg-spec for PKG from `package-vc-selected-packages'." | ||
| 201 | (cdr (assoc pkg package-vc-selected-packages #'string=))) | ||
| 202 | |||
| 203 | (defun package-vc-tests-package-lisp-dir (pkg) | ||
| 204 | "Return a Lisp directory of PKG." | ||
| 205 | (and-let* ((checkout-dir (car (alist-get pkg package-vc-tests-packages)))) | ||
| 206 | (if-let* ((lisp-dir (cadr (alist-get pkg package-vc-tests-packages)))) | ||
| 207 | (expand-file-name lisp-dir checkout-dir) | ||
| 208 | checkout-dir))) | ||
| 209 | |||
| 210 | (defun package-vc-tests-package-main-file (pkg) | ||
| 211 | "Return a main file of PKG." | ||
| 212 | (file-name-concat (package-vc-tests-package-lisp-dir pkg) | ||
| 213 | (format "%s.el" pkg))) | ||
| 214 | |||
| 215 | ;; When `package-vc-upgrade', `package-vc-rebuild', or other a | ||
| 216 | ;; package-vc function re-compiles a package's source the package also | ||
| 217 | ;; reloaded [1] to ensure that the most recent version of compiled code | ||
| 218 | ;; is available to Emacs. Some tests add markers in `load-history' | ||
| 219 | ;; before executing such functions. And then follow up tests use these | ||
| 220 | ;; markers to assert that expected package files are in correct places | ||
| 221 | ;; in the `load-history'. | ||
| 222 | ;; | ||
| 223 | ;; [1] Only when a file has been previously loaded. | ||
| 224 | |||
| 225 | (defun package-vc-tests-load-history-marker (name) | ||
| 226 | "Return a `load-history' marker with NAME." | ||
| 227 | (file-truename | ||
| 228 | (expand-file-name (symbol-name name) package-vc-tests-dir))) | ||
| 229 | |||
| 230 | (defun package-vc-tests-load-history-pattern (pkg type) | ||
| 231 | "Return a regexp pattern for PKG's file of TYPE." | ||
| 232 | (pcase type | ||
| 233 | (:autoloads | ||
| 234 | (rx (literal (file-truename | ||
| 235 | (file-name-concat | ||
| 236 | package-user-dir | ||
| 237 | (symbol-name pkg) | ||
| 238 | (format "%s-autoloads.el" pkg)))) | ||
| 239 | eos)) | ||
| 240 | (:main | ||
| 241 | (rx (literal (file-truename | ||
| 242 | (package-vc-tests-package-main-file pkg))) | ||
| 243 | eos)) | ||
| 244 | (:main-compiled | ||
| 245 | (rx (literal (file-truename | ||
| 246 | (package-vc-tests-package-main-file pkg))) | ||
| 247 | "c" eos)) | ||
| 248 | (:marker | ||
| 249 | (regexp-quote (file-truename | ||
| 250 | (package-vc-tests-load-history-marker pkg)))))) | ||
| 251 | |||
| 252 | (defun package-vc-tests-load-history-interesting-entries () | ||
| 253 | "Return interesting entries in `load-history'. | ||
| 254 | An entry in `load-history' is interesting when it starts with | ||
| 255 | `package-vc-tests-dir'." | ||
| 256 | (let ((interesting-entry | ||
| 257 | (rx bos (literal (file-truename package-vc-tests-dir))))) | ||
| 258 | (mapcan | ||
| 259 | (lambda (ent) | ||
| 260 | (and (consp ent) | ||
| 261 | (stringp (car ent)) | ||
| 262 | (let ((file-name (file-truename (car ent)))) | ||
| 263 | (and (string-match interesting-entry file-name) | ||
| 264 | (list file-name))))) | ||
| 265 | load-history))) | ||
| 266 | |||
| 267 | (defun package-vc-tests-load-history-position (pkg type) | ||
| 268 | "Return a PKG's file of TYPE position in `load-history'. | ||
| 269 | If TYPE is `:autoloads' return a position of a PKG autoloads file. | ||
| 270 | Otherwise, if TYPE is `:main' return a position of PKG main file (not | ||
| 271 | compiled). Otherwise, if TYPE is `:main-compiled' return a position of | ||
| 272 | PKG compiled main file. Otherwise, if TYPE is `:marker' return a | ||
| 273 | position of a marker PKG." | ||
| 274 | (let ((pkg-file (package-vc-tests-load-history-pattern pkg type))) | ||
| 275 | (cl-position-if | ||
| 276 | (lambda (file) (string-match pkg-file file)) | ||
| 277 | (package-vc-tests-load-history-interesting-entries)))) | ||
| 278 | |||
| 279 | (defun package-vc-tests-explain-load-history-position (pkg type) | ||
| 280 | "Explain why `package-vc-tests-load-history' failed for PKG of TYPE." | ||
| 281 | (let ((pattern | ||
| 282 | (concat "..." | ||
| 283 | (substring | ||
| 284 | (package-vc-tests-load-history-pattern pkg type) | ||
| 285 | (length (regexp-quote | ||
| 286 | (file-truename package-vc-tests-dir)))))) | ||
| 287 | (reason | ||
| 288 | (if-let* ((pos (package-vc-tests-load-history-position | ||
| 289 | pkg type))) | ||
| 290 | `(found in load-history at pos ,pos) | ||
| 291 | '(not found in load-history))) | ||
| 292 | (entries | ||
| 293 | (cl-loop | ||
| 294 | with len = (length (file-truename package-vc-tests-dir)) | ||
| 295 | for hist in (package-vc-tests-load-history-interesting-entries) | ||
| 296 | collect (concat "..." (substring hist len))))) | ||
| 297 | (append (list 'pattern pattern) reason (list entries)))) | ||
| 298 | |||
| 299 | (put #'package-vc-tests-load-history-position | ||
| 300 | 'ert-explainer | ||
| 301 | #'package-vc-tests-explain-load-history-position) | ||
| 302 | |||
| 303 | (defun package-vc-tests-log-buffer-name (pkg type) | ||
| 304 | "Return name for action TYPE log buffer for PKG . | ||
| 305 | See `package-vc--build-documentation' and `package-vc--make' for format | ||
| 306 | names." | ||
| 307 | (format " *package-vc %s: %s*" type pkg)) | ||
| 308 | |||
| 309 | (defun package-vc-tests-log-buffer-exists (pkg type) | ||
| 310 | "Return non-nil when log buffer for action TYPE exists for PKG." | ||
| 311 | (when-let* ((name (package-vc-tests-log-buffer-name pkg type))) | ||
| 312 | (get-buffer name))) | ||
| 313 | |||
| 314 | (defun package-vc-tests-explain-log-buffer (pkg type) | ||
| 315 | "Explain why `package-vc-tests-log-buffer-exists' failed for TYPE action for PKG." | ||
| 316 | (if-let* ((name (package-vc-tests-log-buffer-name pkg type)) | ||
| 317 | (buffer (get-buffer name)) | ||
| 318 | (sep (make-string 80 ?-))) | ||
| 319 | (progn | ||
| 320 | (message "package-vc-tests: Contents of log-buffer %s\n%s\n%s\n%s" | ||
| 321 | name | ||
| 322 | sep | ||
| 323 | (with-current-buffer buffer | ||
| 324 | (buffer-string)) | ||
| 325 | sep) | ||
| 326 | `(log-buffer ,name exists)) | ||
| 327 | `(log-buffer ,name does not exist))) | ||
| 328 | |||
| 329 | (put #'package-vc-tests-log-buffer-exists | ||
| 330 | 'ert-explainer | ||
| 331 | #'package-vc-tests-explain-log-buffer) | ||
| 332 | |||
| 333 | (defun package-vc-tests-elc-files (pkg) | ||
| 334 | "Return elc files for PKG." | ||
| 335 | (when-let* ((dir (package-vc-tests-package-lisp-dir pkg))) | ||
| 336 | (directory-files dir nil (rx ".elc" string-end)))) | ||
| 337 | |||
| 338 | (defun package-vc-tests-assert-elc (pkg) | ||
| 339 | "Assert that PKG has correct .elc files in." | ||
| 340 | (let* ((dir (package-vc-tests-package-lisp-dir pkg)) | ||
| 341 | (elc-files (should (package-vc-tests-elc-files pkg))) | ||
| 342 | (autoloads-rx (rx (literal (format "%s-autoloads.elc" pkg)) | ||
| 343 | string-end))) | ||
| 344 | (should-not (cl-find-if (lambda (elc) | ||
| 345 | (string-match autoloads-rx elc)) | ||
| 346 | elc-files)) | ||
| 347 | (dolist (elc-file elc-files) | ||
| 348 | (delete-file (expand-file-name elc-file dir))))) | ||
| 349 | |||
| 350 | (defun package-vc-tests-assert-package-alist (pkg version) | ||
| 351 | "Assert that PKG entry in `package-alist' have correct VERSION and dir." | ||
| 352 | (let ((pkg-desc (should (cadr (assq pkg package-alist))))) | ||
| 353 | (should (equal (file-name-as-directory | ||
| 354 | (expand-file-name (format "%s" pkg) | ||
| 355 | package-user-dir)) | ||
| 356 | (file-name-as-directory | ||
| 357 | (package-desc-dir pkg-desc)))) | ||
| 358 | (should (equal (list pkg version) | ||
| 359 | (list pkg (package-desc-version pkg-desc)))))) | ||
| 360 | |||
| 361 | (defun package-vc-tests-reset-head^ (pkg) | ||
| 362 | "Reset to HEAD^ checkout for PKG." | ||
| 363 | (let ((default-directory (cadr (assoc pkg package-vc-tests-packages)))) | ||
| 364 | (vc-git-command nil 0 nil "reset" "--hard" "HEAD^"))) | ||
| 365 | |||
| 366 | (defun package-vc-tests-package-head (pkg) | ||
| 367 | "Return HEAD revisions of a PKG." | ||
| 368 | (let ((default-directory (cadr (assoc pkg package-vc-tests-packages)))) | ||
| 369 | (vc-git-working-revision nil))) | ||
| 370 | |||
| 371 | (defun package-vc-tests-make-spec (pkg) | ||
| 372 | "Return a pkg-spec for PKG." | ||
| 373 | (let ((lisp-dir | ||
| 374 | (cadr (alist-get pkg package-vc-tests-packages)))) | ||
| 375 | (append | ||
| 376 | (list pkg | ||
| 377 | :url (car package-vc-tests-repository) | ||
| 378 | :doc (let ((doc-file (format "%s.texi" pkg))) | ||
| 379 | (if lisp-dir | ||
| 380 | (file-name-concat lisp-dir doc-file) | ||
| 381 | doc-file)) | ||
| 382 | :make (format "build-%s" pkg) | ||
| 383 | :shell-command (format "touch %s.cmd-build" pkg)) | ||
| 384 | (and lisp-dir | ||
| 385 | (not (member lisp-dir '("lisp" "src"))) | ||
| 386 | (list :lisp-dir lisp-dir))))) | ||
| 387 | |||
| 388 | (defun package-vc-with-tests-environment (pkg function) | ||
| 389 | "Call FUNCTION with no arguments within a test environment set up for PKG." | ||
| 390 | ;; Create a test package sources repository, based on skeleton files | ||
| 391 | ;; in directory package-vc-resources. Before executing body make sure | ||
| 392 | ;; that: | ||
| 393 | ;; | ||
| 394 | ;; - `package' has been initialised, and there are no | ||
| 395 | ;; `package-archives' defined | ||
| 396 | (let* ((package-archives (unless package--initialized | ||
| 397 | (let (package-archives) | ||
| 398 | (package-initialize) | ||
| 399 | (package-vc--archives-initialize)) | ||
| 400 | nil)) | ||
| 401 | ;; - create a temporary location for packages and test files | ||
| 402 | (package-vc-tests-dir | ||
| 403 | (expand-file-name | ||
| 404 | (make-temp-file "package-vc-tests-" | ||
| 405 | t | ||
| 406 | (format-time-string "-%Y%m%d.%H%M%S.%3N")))) | ||
| 407 | ;; - packages are installed into a test directory | ||
| 408 | (package-user-dir (expand-file-name "elpa" | ||
| 409 | package-vc-tests-dir)) | ||
| 410 | ;; - define test packages, their checkout locations, lisp | ||
| 411 | ;; directories, and install functions | ||
| 412 | (package-vc-tests-packages (package-vc-tests-packages)) | ||
| 413 | ;; - create a test package bundle | ||
| 414 | (package-vc-tests-repository | ||
| 415 | (let* ((pkg-name (symbol-name pkg)) | ||
| 416 | (suffix (and (string-match | ||
| 417 | (rx ?- (group (1+ (not ?-))) eos) | ||
| 418 | pkg-name) | ||
| 419 | (match-string 1 pkg-name)))) | ||
| 420 | (package-vc-tests-create-repository | ||
| 421 | suffix (cadr (alist-get pkg package-vc-tests-packages))))) | ||
| 422 | ;; - find all packages that are present in a test ELPA | ||
| 423 | (package-vc-tests-elpa-packages | ||
| 424 | (cl-loop | ||
| 425 | for (name _ _ fn) in package-vc-tests-packages | ||
| 426 | when (memq | ||
| 427 | fn | ||
| 428 | '(package-vc-tests-install-from-elpa | ||
| 429 | package-vc-tests-checkout-from-elpa-install-from-checkout)) | ||
| 430 | collect name)) | ||
| 431 | ;; - make test packages recognisable by `package' and | ||
| 432 | ;; `package-vc' internals: | ||
| 433 | (package-archive-contents | ||
| 434 | (mapcar | ||
| 435 | (lambda (pkg) | ||
| 436 | (list pkg | ||
| 437 | (package-desc-create | ||
| 438 | :name pkg | ||
| 439 | :version '(0 2) | ||
| 440 | :reqs '((emacs (30.1))) | ||
| 441 | :kind 'tar | ||
| 442 | :archive "test-elpa" | ||
| 443 | :extras | ||
| 444 | (list | ||
| 445 | '(:maintainer | ||
| 446 | ("Test Maintainer" | ||
| 447 | . "test-maintainer@test-domain.org")) | ||
| 448 | (cons :url (car package-vc-tests-repository)) | ||
| 449 | (cons :commit (cadr package-vc-tests-repository)) | ||
| 450 | (cons :revdesc (substring | ||
| 451 | (cadr package-vc-tests-repository) | ||
| 452 | 0 12)))))) | ||
| 453 | package-vc-tests-elpa-packages)) | ||
| 454 | ;; Branch needs to be specified in a pkg-spec, as cloning from | ||
| 455 | ;; a bundle won't checkout a default branch. | ||
| 456 | (package-vc--archive-spec-alists | ||
| 457 | (list | ||
| 458 | (cons 'test-elpa | ||
| 459 | (mapcar #'package-vc-tests-make-spec | ||
| 460 | package-vc-tests-elpa-packages)))) | ||
| 461 | (package-vc--archive-data-alist | ||
| 462 | '((test-elpa :version 1 :default-vc Git))) | ||
| 463 | ;; - `vc-guess-backend-url' is recognising bundles as `Git' | ||
| 464 | ;; repositories: | ||
| 465 | (vc-clone-heuristic-alist | ||
| 466 | `((,(rx "test-package-" (1+ digit) ".bundle" eos) | ||
| 467 | . Git) | ||
| 468 | ,@vc-clone-heuristic-alist)) | ||
| 469 | ;; - ensure that `package-alist' and | ||
| 470 | ;; `package-vc-selected-packages' are empty | ||
| 471 | (package-alist '()) | ||
| 472 | (package-vc-selected-packages '()) | ||
| 473 | ;; - don't save any customization | ||
| 474 | (user-init-file nil) | ||
| 475 | (custom-file nil) | ||
| 476 | ;; - don't register projects | ||
| 477 | (package-vc-register-as-project nil) | ||
| 478 | ;; - allow build commands | ||
| 479 | (package-vc-allow-build-commands t) | ||
| 480 | ;; - FIXME: something sets `default-directory' to last | ||
| 481 | ;; checkout directory after `package-vc-checkout', which | ||
| 482 | ;; causes problems when this function deletes the temporary | ||
| 483 | ;; directory after body execution. | ||
| 484 | (default-directory package-vc-tests-dir)) | ||
| 485 | (funcall function))) | ||
| 486 | |||
| 487 | (defun package-vc-tests-environment-tear-down (pkg) | ||
| 488 | "Tear down test environment for PKG. | ||
| 489 | Unbind package defined symbols, and remove package defined features and | ||
| 490 | entries from `load-path',`load-history', and `Info-directory-list'. | ||
| 491 | Delete temporary directories and buffers produced by tests, except for | ||
| 492 | when PKG matches `package-vc-tests-preserve-artefacts'." | ||
| 493 | (let ((pattern (rx string-start (literal package-vc-tests-dir)))) | ||
| 494 | (dolist (entry load-history) | ||
| 495 | (when-let* ((file (car-safe entry)) | ||
| 496 | ((stringp file)) | ||
| 497 | ((string-match pattern file))) | ||
| 498 | (dolist (elt (cdr entry)) | ||
| 499 | (pcase elt | ||
| 500 | (`(defun . ,fun) | ||
| 501 | (fmakunbound fun)) | ||
| 502 | (`(provide . ,feat) | ||
| 503 | (setq features (cl-remove feat features))) | ||
| 504 | ((and (pred symbolp) | ||
| 505 | (pred boundp)) | ||
| 506 | (makunbound elt)))))) | ||
| 507 | (setq load-path (cl-remove-if | ||
| 508 | (lambda (path) | ||
| 509 | (and (stringp path) | ||
| 510 | (string-match pattern path))) | ||
| 511 | load-path) | ||
| 512 | load-history (cl-remove-if | ||
| 513 | (lambda (entry) | ||
| 514 | (and-let* ((path (car-safe entry)) | ||
| 515 | (_ (stringp path))) | ||
| 516 | (string-match pattern path))) | ||
| 517 | load-history) | ||
| 518 | Info-directory-list (cl-remove-if | ||
| 519 | (lambda (dir) | ||
| 520 | (and (stringp dir) | ||
| 521 | (string-match pattern dir))) | ||
| 522 | Info-directory-list))) | ||
| 523 | (let ((buffers | ||
| 524 | (delq nil | ||
| 525 | (mapcar (lambda (type) | ||
| 526 | (get-buffer | ||
| 527 | (package-vc-tests-log-buffer-name type | ||
| 528 | pkg))) | ||
| 529 | '(doc make))))) | ||
| 530 | (if (or (memq package-vc-tests-preserve-artefacts `(t ,pkg)) | ||
| 531 | (and (listp package-vc-tests-preserve-artefacts) | ||
| 532 | (memq pkg package-vc-tests-preserve-artefacts))) | ||
| 533 | (message | ||
| 534 | "package-vc-tests: preserving temporary directory: %s%s" | ||
| 535 | package-vc-tests-dir | ||
| 536 | (and buffers (format " and buffers: %s" buffers))) | ||
| 537 | (delete-directory package-vc-tests-dir t) | ||
| 538 | (dolist (buffer buffers) | ||
| 539 | (kill-buffer buffer))))) | ||
| 540 | |||
| 541 | (defun package-vc-with-installed-tests (pkg function) | ||
| 542 | "Call FUNCTION with PKG installed in a test environment. | ||
| 543 | FUNCTION should have no arguments." | ||
| 544 | (package-vc-with-tests-environment | ||
| 545 | pkg (lambda () | ||
| 546 | (unwind-protect | ||
| 547 | (progn | ||
| 548 | (funcall (or (caddr (alist-get pkg package-vc-tests-packages)) | ||
| 549 | (lambda (name) | ||
| 550 | (ert-fail | ||
| 551 | (format | ||
| 552 | "Cannot find %s in package-vc-tests-packages" | ||
| 553 | name)))) | ||
| 554 | pkg) | ||
| 555 | (funcall function)) | ||
| 556 | (package-vc-tests-environment-tear-down pkg))))) | ||
| 557 | |||
| 558 | (defun package-vc-tests-install-from-elpa (pkg) | ||
| 559 | "Install PKG with `package-vc-install'." | ||
| 560 | (push (list (package-vc-tests-load-history-marker 'install-begin)) | ||
| 561 | load-history) | ||
| 562 | (should (eq t (package-vc-install pkg))) | ||
| 563 | (push (list (package-vc-tests-load-history-marker 'install-end)) | ||
| 564 | load-history) | ||
| 565 | (should-not (package-vc-tests-package-spec pkg))) | ||
| 566 | |||
| 567 | (defun package-vc-tests-install-from-spec (pkg) | ||
| 568 | "Install PKG with `package-vc-install' (not on ELPA)." | ||
| 569 | (push (list (package-vc-tests-load-history-marker 'install-begin)) | ||
| 570 | load-history) | ||
| 571 | (should (eq t (package-vc-install (package-vc-tests-make-spec pkg)))) | ||
| 572 | (push (list (package-vc-tests-load-history-marker 'install-end)) | ||
| 573 | load-history) | ||
| 574 | (should (equal (car package-vc-tests-repository) | ||
| 575 | (plist-get (package-vc-tests-package-spec pkg) | ||
| 576 | :url)))) | ||
| 577 | |||
| 578 | (defun package-vc-tests-checkout-from-elpa-install-from-checkout (pkg) | ||
| 579 | "Install PKG with `package-vc-install-from-checkout'. | ||
| 580 | Make checkout with `package-vc-checkout'." | ||
| 581 | (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages)))) | ||
| 582 | (let* ((uniquify-buffer-name-style nil) | ||
| 583 | (buffer (package-vc-checkout (package-vc-tests-package-desc | ||
| 584 | pkg) | ||
| 585 | checkout-dir))) | ||
| 586 | (should (bufferp buffer)) | ||
| 587 | (should (string-prefix-p (symbol-name pkg) (buffer-name buffer)))) | ||
| 588 | (push (list (package-vc-tests-load-history-marker 'install-begin)) | ||
| 589 | load-history) | ||
| 590 | (should (eq t | ||
| 591 | (package-vc-install-from-checkout checkout-dir))) | ||
| 592 | (push (list (package-vc-tests-load-history-marker 'install-end)) | ||
| 593 | load-history) | ||
| 594 | (let ((extras (package-desc-extras (package-vc-tests-package-desc pkg t)))) | ||
| 595 | (should (equal checkout-dir (alist-get :vc-dir extras)))))) | ||
| 596 | |||
| 597 | (defun package-vc-tests-checkout-with-git-install-from-checkout (pkg) | ||
| 598 | "Install PKG with `package-vc-install-from-checkout'. | ||
| 599 | Make checkout with git(1)." | ||
| 600 | (let ((checkout-dir (car (alist-get pkg package-vc-tests-packages)))) | ||
| 601 | (vc-git-clone (car package-vc-tests-repository) | ||
| 602 | checkout-dir | ||
| 603 | "master") | ||
| 604 | (push (list (package-vc-tests-load-history-marker 'install-begin)) | ||
| 605 | load-history) | ||
| 606 | (should (eq t | ||
| 607 | (package-vc-install-from-checkout checkout-dir | ||
| 608 | (symbol-name pkg)))) | ||
| 609 | (push (list (package-vc-tests-load-history-marker 'install-end)) | ||
| 610 | load-history) | ||
| 611 | (let ((extras (package-desc-extras (package-vc-tests-package-desc pkg t)))) | ||
| 612 | (should (equal checkout-dir (alist-get :vc-dir extras)))))) | ||
| 613 | |||
| 614 | ;; Some of VC commands used by package-vc execute VC operations | ||
| 615 | ;; asynchronously. When such an operation executes as a part of test | ||
| 616 | ;; body, the test needs to wait for the operation to finish before | ||
| 617 | ;; asserting post conditions. The maximum wait time should be at least | ||
| 618 | ;; a single order of magnitude higher than what the operation usually | ||
| 619 | ;; takes. This decreases probability of false positives (for example | ||
| 620 | ;; when execution takes place on a busy machine). On the other hand the | ||
| 621 | ;; value cannot be too large to ensure reasonable execution time in case | ||
| 622 | ;; of a legitimate failure. | ||
| 623 | |||
| 624 | (defmacro package-vc-tests-package-vc-async-wait (seconds count flags &rest body) | ||
| 625 | "Wait up to SECONDS for COUNT async vc commands with FLAGS called by BODY. | ||
| 626 | Return nil on timeout or the value of last form in BODY." | ||
| 627 | (declare (indent 3)) | ||
| 628 | (let ((count-sym (make-symbol "count")) | ||
| 629 | (post-vc-command-sym (make-symbol "post-vc-command"))) | ||
| 630 | `(let* ((,count-sym ,count) | ||
| 631 | (,post-vc-command-sym | ||
| 632 | (lambda (command _ command-flags) | ||
| 633 | ;; A crude filter for vc commands | ||
| 634 | (when (and (equal command vc-git-program) | ||
| 635 | (cl-every (lambda (flag) | ||
| 636 | (member flag command-flags)) | ||
| 637 | ,flags)) | ||
| 638 | (decf ,count-sym))))) | ||
| 639 | (add-hook 'vc-post-command-functions ,post-vc-command-sym 100) | ||
| 640 | (unwind-protect | ||
| 641 | (with-timeout (,seconds nil) | ||
| 642 | (prog1 (progn ,@body) | ||
| 643 | (while (/= ,count-sym 0) | ||
| 644 | (accept-process-output nil 0.01)))) | ||
| 645 | (remove-hook 'vc-post-command-functions ,post-vc-command-sym))))) | ||
| 646 | |||
| 647 | (defmacro package-vc-test-deftest (name args &rest body) | ||
| 648 | "For each package under test define a test with NAME. | ||
| 649 | Use function `package-vc-tests-packages' to obtain packages under test. | ||
| 650 | Execute BODY as a test body with a package under test installed. Bind | ||
| 651 | car of ARGS (a symbol) to name of the package." | ||
| 652 | (declare (debug (&define [&name "test@" symbolp] | ||
| 653 | sexp | ||
| 654 | def-body)) | ||
| 655 | (indent 2)) | ||
| 656 | (when (length< args 1) | ||
| 657 | (error "`package-vc' tests have to take at least one argument")) | ||
| 658 | (unless (symbolp (car-safe args)) | ||
| 659 | (error "`package-vc' tests first argument has to be a symbol")) | ||
| 660 | (let ((file (or (macroexp-file-name) buffer-file-name)) | ||
| 661 | (tests '()) (fn (gensym))) | ||
| 662 | (dolist (pkg (package-vc-tests-packages)) | ||
| 663 | (let ((name (intern (format "package-vc-tests-%s/%s" name pkg)))) | ||
| 664 | (push | ||
| 665 | `(ert-set-test | ||
| 666 | ',name | ||
| 667 | (make-ert-test | ||
| 668 | :name ',name | ||
| 669 | :tags '(package-vc) | ||
| 670 | :file-name ,file | ||
| 671 | :body | ||
| 672 | (lambda () | ||
| 673 | (package-vc-with-installed-tests | ||
| 674 | ',pkg (funcall ,fn ',pkg)) | ||
| 675 | nil))) | ||
| 676 | tests))) | ||
| 677 | `(let ((,fn (lambda (,(car args)) | ||
| 678 | (cl-macrolet ((skip-when (form) `(ert--skip-when ,form)) | ||
| 679 | (skip-unless (form) `(ert--skip-unless ,form))) | ||
| 680 | (lambda () ,@body))))) | ||
| 681 | ,@tests))) | ||
| 682 | |||
| 683 | (package-vc-test-deftest install-post-conditions (pkg) | ||
| 684 | (let ((install-begin | ||
| 685 | (should (package-vc-tests-load-history-position | ||
| 686 | 'install-begin :marker))) | ||
| 687 | (install-end | ||
| 688 | (should (package-vc-tests-load-history-position | ||
| 689 | 'install-end :marker))) | ||
| 690 | (autoloads-pos | ||
| 691 | (should (package-vc-tests-load-history-position | ||
| 692 | pkg :autoloads)))) | ||
| 693 | (should (< install-end autoloads-pos install-begin)) | ||
| 694 | (should-not (package-vc-tests-load-history-position | ||
| 695 | pkg :main)) | ||
| 696 | (should-not (package-vc-tests-load-history-position | ||
| 697 | pkg :main-compiled))) | ||
| 698 | (should (equal (package-vc--main-file | ||
| 699 | (package-vc-tests-package-desc pkg t)) | ||
| 700 | (package-vc-tests-package-main-file pkg))) | ||
| 701 | (should (equal (package-vc-commit | ||
| 702 | (package-vc-tests-package-desc pkg t)) | ||
| 703 | (cadr package-vc-tests-repository))) | ||
| 704 | (package-vc-tests-assert-elc pkg) | ||
| 705 | (package-vc-tests-assert-package-alist pkg '(0 2))) | ||
| 706 | |||
| 707 | (package-vc-test-deftest require (pkg) | ||
| 708 | (should (fboundp (intern (format "%s-func" pkg)))) | ||
| 709 | (should (autoloadp | ||
| 710 | (symbol-function (intern (format "%s-func" pkg))))) | ||
| 711 | (should (require pkg)) | ||
| 712 | (should (fboundp (intern (format "%s-func" pkg)))) | ||
| 713 | (should-not (autoloadp | ||
| 714 | (symbol-function (intern (format "%s-func" pkg))))) | ||
| 715 | (should-not (fboundp (intern (format "%s-old-func" pkg)))) | ||
| 716 | (should-not (package-vc-tests-load-history-position | ||
| 717 | pkg :main)) | ||
| 718 | (let ((install-end | ||
| 719 | (should (package-vc-tests-load-history-position | ||
| 720 | 'install-end :marker))) | ||
| 721 | (main-compiled-pos | ||
| 722 | (should (package-vc-tests-load-history-position | ||
| 723 | pkg :main-compiled)))) | ||
| 724 | (should (< main-compiled-pos install-end)))) | ||
| 725 | |||
| 726 | (package-vc-test-deftest upgrade (pkg) | ||
| 727 | (let ((head (package-vc-tests-package-head pkg))) | ||
| 728 | (package-vc-tests-reset-head^ pkg) | ||
| 729 | (push (list (package-vc-tests-load-history-marker | ||
| 730 | 'upgrade-begin)) | ||
| 731 | load-history) | ||
| 732 | (should | ||
| 733 | (package-vc-tests-package-vc-async-wait 5 1 '("pull") | ||
| 734 | (package-vc-upgrade (package-vc-tests-package-desc pkg t)) | ||
| 735 | t)) | ||
| 736 | (push (list (package-vc-tests-load-history-marker | ||
| 737 | 'upgrade-end)) | ||
| 738 | load-history) | ||
| 739 | (should-not (package-vc-tests-load-history-position | ||
| 740 | pkg :main)) | ||
| 741 | (should-not (package-vc-tests-load-history-position | ||
| 742 | pkg :main-compiled)) | ||
| 743 | (let ((upgrade-begin | ||
| 744 | (should (package-vc-tests-load-history-position | ||
| 745 | 'upgrade-begin :marker))) | ||
| 746 | (upgrade-end | ||
| 747 | (should (package-vc-tests-load-history-position | ||
| 748 | 'upgrade-end :marker))) | ||
| 749 | (autoloads-pos | ||
| 750 | (should (package-vc-tests-load-history-position | ||
| 751 | pkg :autoloads)))) | ||
| 752 | (should (< upgrade-end autoloads-pos upgrade-begin))) | ||
| 753 | (let ((func (intern (format "%s-func" pkg)))) | ||
| 754 | (should (fboundp func)) | ||
| 755 | (should (autoloadp | ||
| 756 | (symbol-function func))) | ||
| 757 | (should (equal "New macro test" | ||
| 758 | (funcall func "test")))) | ||
| 759 | (should-not (fboundp (intern (format "%s-old-func" pkg)))) | ||
| 760 | (should (equal head | ||
| 761 | (package-vc-tests-package-head pkg)))) | ||
| 762 | (package-vc-tests-assert-elc pkg) | ||
| 763 | (package-vc-tests-assert-package-alist pkg '(0 2))) | ||
| 764 | |||
| 765 | (package-vc-test-deftest upgrade-after-require (pkg) | ||
| 766 | (should (require pkg)) | ||
| 767 | (let ((head (package-vc-tests-package-head pkg))) | ||
| 768 | (package-vc-tests-reset-head^ pkg) | ||
| 769 | (push (list (package-vc-tests-load-history-marker | ||
| 770 | 'upgrade-begin)) | ||
| 771 | load-history) | ||
| 772 | (should | ||
| 773 | (package-vc-tests-package-vc-async-wait 5 1 '("pull") | ||
| 774 | (package-vc-upgrade (package-vc-tests-package-desc pkg t)) | ||
| 775 | t)) | ||
| 776 | (push (list (package-vc-tests-load-history-marker | ||
| 777 | 'upgrade-end)) | ||
| 778 | load-history) | ||
| 779 | (let ((upgrade-begin | ||
| 780 | (should (package-vc-tests-load-history-position | ||
| 781 | 'upgrade-begin :marker))) | ||
| 782 | (upgrade-end | ||
| 783 | (should (package-vc-tests-load-history-position | ||
| 784 | 'upgrade-end :marker))) | ||
| 785 | (autoloads-pos | ||
| 786 | (should (package-vc-tests-load-history-position | ||
| 787 | pkg :autoloads))) | ||
| 788 | (main-pos | ||
| 789 | (should (package-vc-tests-load-history-position | ||
| 790 | pkg :main))) | ||
| 791 | (main-compiled-pos | ||
| 792 | (should (package-vc-tests-load-history-position | ||
| 793 | pkg :main-compiled)))) | ||
| 794 | (should (< upgrade-end autoloads-pos upgrade-begin)) | ||
| 795 | (should (< upgrade-end main-pos upgrade-begin)) | ||
| 796 | (should (< upgrade-end main-compiled-pos upgrade-begin))) | ||
| 797 | (let ((func (intern (format "%s-func" pkg)))) | ||
| 798 | (should (fboundp func)) | ||
| 799 | (should-not (autoloadp | ||
| 800 | (symbol-function func))) | ||
| 801 | (should (equal "New macro test" | ||
| 802 | (funcall func "test")))) | ||
| 803 | (should-not (fboundp (intern (format "%s-old-func" pkg)))) | ||
| 804 | (should (equal head | ||
| 805 | (package-vc-tests-package-head pkg)))) | ||
| 806 | (package-vc-tests-assert-elc pkg) | ||
| 807 | (package-vc-tests-assert-package-alist pkg '(0 2))) | ||
| 808 | |||
| 809 | (package-vc-test-deftest upgrade-all (pkg) | ||
| 810 | (let ((head (package-vc-tests-package-head pkg))) | ||
| 811 | (package-vc-tests-reset-head^ pkg) | ||
| 812 | (push (list (package-vc-tests-load-history-marker | ||
| 813 | 'upgrade-all-begin)) | ||
| 814 | load-history) | ||
| 815 | (should | ||
| 816 | (package-vc-tests-package-vc-async-wait 5 1 '("pull") | ||
| 817 | (package-vc-upgrade-all) | ||
| 818 | t)) | ||
| 819 | (push (list (package-vc-tests-load-history-marker | ||
| 820 | 'upgrade-all-end)) | ||
| 821 | load-history) | ||
| 822 | (should-not (package-vc-tests-load-history-position | ||
| 823 | pkg :main)) | ||
| 824 | (should-not (package-vc-tests-load-history-position | ||
| 825 | pkg :main-compiled)) | ||
| 826 | (let ((upgrade-begin | ||
| 827 | (should (package-vc-tests-load-history-position | ||
| 828 | 'upgrade-all-begin :marker))) | ||
| 829 | (upgrade-end | ||
| 830 | (should (package-vc-tests-load-history-position | ||
| 831 | 'upgrade-all-end :marker))) | ||
| 832 | (autoloads-pos | ||
| 833 | (should (package-vc-tests-load-history-position | ||
| 834 | pkg :autoloads)))) | ||
| 835 | (should (< upgrade-end autoloads-pos upgrade-begin))) | ||
| 836 | (let ((func (intern (format "%s-func" pkg)))) | ||
| 837 | (should (fboundp func)) | ||
| 838 | (should (autoloadp | ||
| 839 | (symbol-function func))) | ||
| 840 | (should (equal "New macro test" | ||
| 841 | (funcall func "test")))) | ||
| 842 | (should-not (fboundp (intern (format "%s-old-func" pkg)))) | ||
| 843 | (should (equal head | ||
| 844 | (package-vc-tests-package-head pkg)))) | ||
| 845 | (package-vc-tests-assert-elc pkg) | ||
| 846 | (package-vc-tests-assert-package-alist pkg '(0 2))) | ||
| 847 | |||
| 848 | (package-vc-test-deftest upgrade-all-after-require (pkg) | ||
| 849 | (should (require pkg)) | ||
| 850 | (let ((head (package-vc-tests-package-head pkg))) | ||
| 851 | (package-vc-tests-reset-head^ pkg) | ||
| 852 | (push (list (package-vc-tests-load-history-marker | ||
| 853 | 'upgrade-all-begin)) | ||
| 854 | load-history) | ||
| 855 | (should | ||
| 856 | (package-vc-tests-package-vc-async-wait 5 1 '("pull") | ||
| 857 | (package-vc-upgrade-all) | ||
| 858 | t)) | ||
| 859 | (push (list (package-vc-tests-load-history-marker | ||
| 860 | 'upgrade-all-end)) | ||
| 861 | load-history) | ||
| 862 | (let ((upgrade-begin | ||
| 863 | (should (package-vc-tests-load-history-position | ||
| 864 | 'upgrade-all-begin :marker))) | ||
| 865 | (upgrade-end | ||
| 866 | (should (package-vc-tests-load-history-position | ||
| 867 | 'upgrade-all-end :marker))) | ||
| 868 | (autoloads-pos | ||
| 869 | (should (package-vc-tests-load-history-position | ||
| 870 | pkg :autoloads))) | ||
| 871 | (main-pos | ||
| 872 | (should (package-vc-tests-load-history-position | ||
| 873 | pkg :main))) | ||
| 874 | (main-compiled-pos | ||
| 875 | (should (package-vc-tests-load-history-position | ||
| 876 | pkg :main-compiled)))) | ||
| 877 | (should (< upgrade-end autoloads-pos upgrade-begin)) | ||
| 878 | (should (< upgrade-end main-pos upgrade-begin)) | ||
| 879 | (should (< upgrade-end main-compiled-pos upgrade-begin))) | ||
| 880 | (let ((func (intern (format "%s-func" pkg)))) | ||
| 881 | (should (fboundp func)) | ||
| 882 | (should-not (autoloadp | ||
| 883 | (symbol-function func))) | ||
| 884 | (should (equal "New macro test" | ||
| 885 | (funcall func "test")))) | ||
| 886 | (should-not (fboundp (intern (format "%s-old-func" pkg)))) | ||
| 887 | (should (equal head | ||
| 888 | (package-vc-tests-package-head pkg)))) | ||
| 889 | (package-vc-tests-assert-elc pkg) | ||
| 890 | (package-vc-tests-assert-package-alist pkg '(0 2))) | ||
| 891 | |||
| 892 | (package-vc-test-deftest rebuild (pkg) | ||
| 893 | (package-vc-tests-reset-head^ pkg) | ||
| 894 | (let ((head (package-vc-tests-package-head pkg))) | ||
| 895 | (package-vc-rebuild | ||
| 896 | (package-vc-tests-package-desc pkg t)) | ||
| 897 | (let ((old-func (intern (format "%s-old-func" pkg)))) | ||
| 898 | (should (fboundp old-func)) | ||
| 899 | (should (autoloadp | ||
| 900 | (symbol-function old-func)))) | ||
| 901 | (let ((func (intern (format "%s-func" pkg)))) | ||
| 902 | (should (fboundp func)) | ||
| 903 | (should (autoloadp | ||
| 904 | (symbol-function func))) | ||
| 905 | (should (equal "Old macro test" | ||
| 906 | (funcall func "test")))) | ||
| 907 | (should (equal head | ||
| 908 | (package-vc-tests-package-head pkg)))) | ||
| 909 | (package-vc-tests-assert-elc pkg) | ||
| 910 | (package-vc-tests-assert-package-alist pkg '(0 1))) | ||
| 911 | |||
| 912 | (package-vc-test-deftest rebuild-after-require (pkg) | ||
| 913 | (should (require pkg)) | ||
| 914 | (package-vc-tests-reset-head^ pkg) | ||
| 915 | (let ((head (package-vc-tests-package-head pkg))) | ||
| 916 | (package-vc-rebuild | ||
| 917 | (package-vc-tests-package-desc pkg t)) | ||
| 918 | (let ((old-func (intern (format "%s-old-func" pkg)))) | ||
| 919 | (should (fboundp old-func)) | ||
| 920 | (should-not (autoloadp | ||
| 921 | (symbol-function old-func)))) | ||
| 922 | (let ((func (intern (format "%s-func" pkg)))) | ||
| 923 | (should (fboundp func)) | ||
| 924 | (should-not (autoloadp | ||
| 925 | (symbol-function func))) | ||
| 926 | (should (equal "Old macro test" | ||
| 927 | (funcall func "test")))) | ||
| 928 | (should (equal head | ||
| 929 | (package-vc-tests-package-head pkg)))) | ||
| 930 | (package-vc-tests-assert-elc pkg) | ||
| 931 | (package-vc-tests-assert-package-alist pkg '(0 1))) | ||
| 932 | |||
| 933 | (package-vc-test-deftest prepare-patch (pkg) | ||
| 934 | ;; Ensure `vc-prepare-patch' respects subject from function argument | ||
| 935 | (let ((vc-prepare-patches-separately nil)) | ||
| 936 | (package-vc-prepare-patch (package-vc-tests-package-desc pkg t) | ||
| 937 | "test-subject" | ||
| 938 | (cdr package-vc-tests-repository)) | ||
| 939 | (let ((message-buffer | ||
| 940 | (should (get-buffer "*unsent mail to Test Maintainer*")))) | ||
| 941 | (should (bufferp message-buffer)) | ||
| 942 | (switch-to-buffer message-buffer) | ||
| 943 | (goto-char (point-min)) | ||
| 944 | (should | ||
| 945 | (string-match | ||
| 946 | (rx | ||
| 947 | "To: Test Maintainer <test-maintainer@test-domain.org>") | ||
| 948 | (buffer-substring (point) (pos-eol)))) | ||
| 949 | (forward-line) | ||
| 950 | (should | ||
| 951 | (string-match | ||
| 952 | (rx "Subject: test-subject") | ||
| 953 | (buffer-substring (point) (pos-eol)))) | ||
| 954 | (let ((kill-buffer-query-functions nil)) | ||
| 955 | (with-current-buffer message-buffer | ||
| 956 | ;; we mark the buffer as unmodified so that `kill-buffer' | ||
| 957 | ;; doesn't complain (interrupting automatic testsx) | ||
| 958 | (set-buffer-modified-p nil)) | ||
| 959 | (kill-buffer message-buffer))))) | ||
| 960 | |||
| 961 | (package-vc-test-deftest log-incoming (pkg) | ||
| 962 | (package-vc-tests-reset-head^ pkg) | ||
| 963 | (should | ||
| 964 | (package-vc-tests-package-vc-async-wait | ||
| 965 | 5 1 '("log" "--decorate") | ||
| 966 | (package-vc-log-incoming (package-vc-tests-package-desc pkg t)) | ||
| 967 | t)) | ||
| 968 | (let ((incoming-buffer (get-buffer "*vc-incoming*")) | ||
| 969 | (pattern (rx (literal | ||
| 970 | (substring | ||
| 971 | (cadr package-vc-tests-repository) | ||
| 972 | 0 7)) | ||
| 973 | (one-or-more any) | ||
| 974 | "Second commit" | ||
| 975 | line-end))) | ||
| 976 | (should (bufferp incoming-buffer)) | ||
| 977 | (switch-to-buffer incoming-buffer) | ||
| 978 | (goto-char (point-min)) | ||
| 979 | (should | ||
| 980 | (string-match | ||
| 981 | pattern | ||
| 982 | (buffer-substring (point) (pos-eol)))) | ||
| 983 | (let (kill-buffer-query-functions) | ||
| 984 | (kill-buffer incoming-buffer)))) | ||
| 985 | |||
| 986 | (package-vc-test-deftest pkg-spec-doc-make-shell-command (pkg) | ||
| 987 | ;; Only `package-vc-install' runs make and shell command | ||
| 988 | (skip-unless (memq (caddr (alist-get pkg package-vc-tests-packages)) | ||
| 989 | '(package-vc-tests-install-from-elpa | ||
| 990 | package-vc-tests-install-from-spec))) | ||
| 991 | (let* ((desc (package-vc-tests-package-desc pkg t)) | ||
| 992 | (checkout-dir (package-vc--checkout-dir desc))) | ||
| 993 | (should (file-exists-p | ||
| 994 | (expand-file-name | ||
| 995 | (format "%s.make-build" pkg) | ||
| 996 | checkout-dir))) | ||
| 997 | (should (file-exists-p | ||
| 998 | (expand-file-name | ||
| 999 | (format "%s.cmd-build" pkg) | ||
| 1000 | checkout-dir)))) | ||
| 1001 | (should-not (package-vc-tests-log-buffer-exists 'doc pkg)) | ||
| 1002 | (should (cl-member-if | ||
| 1003 | (lambda (dir) | ||
| 1004 | (and (stringp dir) | ||
| 1005 | (string-prefix-p package-vc-tests-dir dir))) | ||
| 1006 | Info-directory-list)) | ||
| 1007 | (let ((info-file | ||
| 1008 | (expand-file-name (format "%s.info" pkg) | ||
| 1009 | (car (alist-get | ||
| 1010 | pkg package-vc-tests-packages))))) | ||
| 1011 | (should (file-exists-p info-file)) | ||
| 1012 | (ert-with-test-buffer | ||
| 1013 | (:name (format "*package-vc-tests: %s.info*" pkg)) | ||
| 1014 | (insert-file-contents info-file) | ||
| 1015 | (goto-char (point-min)) | ||
| 1016 | (should (re-search-forward | ||
| 1017 | (format "First chapter for %s" pkg))) | ||
| 1018 | (should (re-search-forward | ||
| 1019 | (format "Second chapter for %s" pkg)))))) | ||
| 1020 | |||
| 1021 | (provide 'package-vc-tests) | ||
| 1022 | ;;; package-vc-tests.el ends here | ||