From 94d5435fc6fdc8990fa064f809a0e328653ff82a Mon Sep 17 00:00:00 2001 From: Paul Pogonyshev Date: Wed, 20 Sep 2023 22:09:05 +0200 Subject: [PATCH] Add function `eldev-inherit-options' aimed at assisting in defining new commands that are in some way similar to existing ones. --- eldev.el | 19 +++++++++++++++++++ test/compile.el | 4 ++-- test/extending.el | 21 +++++++++++++++++++++ test/project-g/Eldev | 15 +++++++++++++++ test/project-g/test/test-g-integration.el | 5 +++++ test/targets.el | 3 +++ test/test.el | 10 +++++++++- 7 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 test/extending.el create mode 100644 test/project-g/test/test-g-integration.el diff --git a/eldev.el b/eldev.el index 27375fc2..634e83d3 100644 --- a/eldev.el +++ b/eldev.el @@ -512,6 +512,25 @@ BODY can contain the following keywords: ,@body) (eldev--register-option ',name ',options ',for-command ',(nreverse keywords))))) +(defun eldev-inherit-options (to-command from-command &optional filter) + "DONOTRELEASE: Document. + +Since 1.7." + (unless (assq from-command eldev--commands) + (error "Unknown command `%s'" from-command)) + (dolist (entry (cdr (assq from-command eldev--options))) + (let ((option (car entry)) + (handler (cdr entry))) + (when filter + (pcase (funcall filter option handler) + ;; All other return values are reserved for future. Ideas: changing option + ;; name, changing (wrapping) handler, providing keywords. + (`t) + (`nil (setf option nil)) + (value (error "Filter function may only return t or nil currently (got `%S' instead)" value)))) + (when option + (eldev--register-option handler option to-command nil))))) + (defmacro eldev-defbooloptions (t-name nil-name variable t-body nil-body &rest common-body) "Define a yes/no (boolean) option. This is only a wrapper over `eldev-defoption'." diff --git a/test/compile.el b/test/compile.el index 27f077bb..be7bce9c 100644 --- a/test/compile.el +++ b/test/compile.el @@ -66,9 +66,9 @@ (ert-deftest eldev-compile-test-files-2 () ;; This project has an additional loading root for tests. - (eldev--test-without-files "project-g" ("test/test-g-1.elc" "test/test-g-util.elc") + (eldev--test-without-files "project-g" ("test/test-g-1.elc" "test/test-g-integration.elc" "test/test-g-util.elc") (eldev--test-run nil ("compile" "--set" "test") - (eldev--test-assert-files project-dir preexisting-files "test/test-g-1.elc" "test/test-g-util.elc") + (eldev--test-assert-files project-dir preexisting-files "test/test-g-1.elc" "test/test-g-integration.elc" "test/test-g-util.elc") (should (= exit-code 0))))) diff --git a/test/extending.el b/test/extending.el new file mode 100644 index 00000000..dd2e5a23 --- /dev/null +++ b/test/extending.el @@ -0,0 +1,21 @@ +(require 'test/common) + + +(ert-deftest eldev-defcommand-1 () + ;; `project-g/Eldev' defines a new command that is like `test', but for a specific file. + (eldev--test-run "project-g" ("test-integration") + (should (string-match-p "passed.+project-g-integration-1" stdout)) + (should (string-match-p "Ran 1 test" stdout)) + (should (= exit-code 0))) + ;; The new command inherits most options from standard `test'. + (eldev--test-run "project-g" ("test-integration" "--stop" "-B" "--expect=1") + (should (string-match-p "passed.+project-g-integration-1" stdout)) + (should (string-match-p "Ran 1 test" stdout)) + (should (= exit-code 0))) + ;; But it doesn't inherit option `--file', as it doesn't make sense for it. + (eldev--test-run "project-g" ("test-integration" "--file" "*.el") + (should (string-match-p "Unknown option .--file." stderr)) + (should (= exit-code 1)))) + + +(provide 'test/extending) diff --git a/test/project-g/Eldev b/test/project-g/Eldev index c6aa055f..c23e45ca 100644 --- a/test/project-g/Eldev +++ b/test/project-g/Eldev @@ -1,2 +1,17 @@ ;; This project deliberately uses additional loading root for its tests. (eldev-add-loading-roots 'test "test") + + +;; Mainly for testing `eldev-parse-command-line' and `eldev-inherit-options' in a more or +;; less realistic setup. Same as command `test', but run tests from a fixed file. +(eldev-defcommand project-g-test-integration (&rest parameters) + :command test-integration + :custom-parsing t + :category testing + (let* ((parsed (eldev-parse-command-line parameters :command 'test-integration)) + (command-line (plist-get parsed :all-options))) + (when (plist-get parsed :without-options) + (signal 'eldev-wrong-command-usage `(t "Too many command parameters"))) + (eldev-test "test-g-integration.el"))) + +(eldev-inherit-options 'test-integration 'test (lambda (option handler) (not (eq handler #'eldev-test-files)))) diff --git a/test/project-g/test/test-g-integration.el b/test/project-g/test/test-g-integration.el new file mode 100644 index 00000000..e384fa68 --- /dev/null +++ b/test/project-g/test/test-g-integration.el @@ -0,0 +1,5 @@ +(require 'test-g-util) + +(ert-deftest project-g-integration-1 () + ;; Basically just as `project-g-1'; important is that it also passes. + (should (equal (project-g-hello) (project-g-test-util-hello)))) diff --git a/test/targets.el b/test/targets.el index 02eccc90..3760c797 100644 --- a/test/targets.el +++ b/test/targets.el @@ -197,6 +197,9 @@ " test/test-g-1.elc [ELC]" " test/test-g-1.el" " [inh] test/test-g-util.elc" + " test/test-g-integration.elc [ELC]" + " test/test-g-integration.el" + " [inh] test/test-g-util.elc" " test/test-g-util.elc [ELC]" " test/test-g-util.el" " [inh] project-g.elc")) diff --git a/test/test.el b/test/test.el index 9f07f99e..af89d047 100644 --- a/test/test.el +++ b/test/test.el @@ -6,6 +6,7 @@ (eldev--test-run "project-a" ("test") (should (string-match-p "passed.+project-a-test-hello" stdout)) (should (string-match-p "passed.+project-a-test-triviality" stdout)) + (should (string-match-p "Ran 2 tests" stdout)) (should (= exit-code 0)))) (ert-deftest eldev-test-project-b-1 () @@ -13,17 +14,20 @@ (eldev--test-run "project-b" ("test") (should (string-match-p "passed.+project-b-test-hello" stdout)) (should (string-match-p "FAILED.+project-b-test-triviality-failing" stdout)) + (should (string-match-p "Ran 2 tests" stdout)) (should (= exit-code 1)))) (ert-deftest eldev-test-project-b-2 () ;; Only one passing test. (eldev--test-run "project-b" ("test" "hello") (should (string-match-p "passed.+project-b-test-hello" stdout)) + (should (string-match-p "Ran 1 test" stdout)) (should (= exit-code 0)))) (ert-deftest eldev-test-project-b-3 () ;; Only one failing test. (eldev--test-run "project-b" ("test" "failing") + (should (string-match-p "Ran 1 test" stdout)) (should (= exit-code 1)))) (ert-deftest eldev-test-project-b-4 () @@ -43,12 +47,16 @@ (eldev--test-run "project-c" ("test") (should (string-match-p "passed.+project-c-test-hello" stdout)) (should (string-match-p "passed.+project-c-test-triviality" stdout)) + (should (string-match-p "Ran 2 tests" stdout)) (should (= exit-code 0)))) (ert-deftest eldev-test-project-g-1 () - ;; One passing test. This project uses a loading root for its tests. + ;; Two passing tests, one is "integration test", but here we run it too. This project + ;; uses a loading root for its tests. (eldev--test-run "project-g" ("test") (should (string-match-p "passed.+project-g-1" stdout)) + (should (string-match-p "passed.+project-g-integration-1" stdout)) + (should (string-match-p "Ran 2 tests" stdout)) (should (= exit-code 0)))) (ert-deftest eldev-test-missing-dependency-1 ()