emacs/test/lisp/eshell/esh-cmd-tests.el

598 lines
23 KiB
EmacsLisp
Raw Normal View History

Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;;; esh-cmd-tests.el --- esh-cmd test suite -*- lexical-binding:t -*-
2024-01-02 09:47:10 +08:00
;; Copyright (C) 2022-2024 Free Software Foundation, Inc.
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Tests for Eshell's command invocation.
;;; Code:
(require 'ert)
(require 'esh-mode)
(require 'eshell)
(require 'eshell-tests-helpers
(expand-file-name "eshell-tests-helpers"
(file-name-directory (or load-file-name
default-directory))))
(defvar eshell-test-value nil)
;;; Tests:
;; Command invocation
(ert-deftest esh-cmd-test/simple-command-result ()
"Test invocation with a simple command."
(eshell-command-result-equal "+ 1 2" 3))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/lisp-command ()
"Test invocation with an elisp command."
(eshell-command-result-equal "(+ 1 2)" 3))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/lisp-command-with-quote ()
"Test invocation with an elisp command containing a quote."
(eshell-command-result-equal "(eq 'foo nil)" nil))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/lisp-command-args ()
"Test invocation with elisp and trailing args.
Test that trailing arguments outside the S-expression are
ignored. e.g. \"(+ 1 2) 3\" => 3"
(eshell-command-result-equal "(+ 1 2) 3" 3))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/subcommand ()
"Test invocation with a simple subcommand."
(eshell-command-result-equal "{+ 1 2}" 3))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/subcommand-args ()
"Test invocation with a subcommand and trailing args.
Test that trailing arguments outside the subcommand are ignored.
e.g. \"{+ 1 2} 3\" => 3"
(eshell-command-result-equal "{+ 1 2} 3" 3))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/subcommand-lisp ()
"Test invocation with an elisp subcommand and trailing args.
Test that trailing arguments outside the subcommand are ignored.
e.g. \"{(+ 1 2)} 3\" => 3"
(eshell-command-result-equal "{(+ 1 2)} 3" 3))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/subcommand-shadow-value ()
"Test that the variable `value' isn't shadowed inside subcommands."
(with-temp-eshell
(with-no-warnings (setq-local value "hello"))
(eshell-match-command-output "echo ${echo $value}"
"hello\n")))
(ert-deftest esh-cmd-test/skip-leading-nils ()
"Test that Eshell skips leading nil arguments for named commands."
(eshell-command-result-equal "$eshell-test-value echo hello" "hello")
(eshell-command-result-equal
"$eshell-test-value $eshell-test-value echo hello" "hello"))
(ert-deftest esh-cmd-test/let-rebinds-after-defer ()
"Test that let-bound values are properly updated after `eshell-defer'.
When inside a `let' block in an Eshell command form, we need to
ensure that deferred commands update any let-bound variables so
they have the correct values when resuming evaluation. See
bug#59469."
(skip-unless (executable-find "echo"))
(with-temp-eshell
(eshell-match-command-output
(concat "{"
" export LOCAL=value; "
" echo \"$LOCAL\"; "
" *echo external; " ; This will throw `eshell-defer'.
" echo \"$LOCAL\"; "
"}")
"value\nexternal\nvalue\n")))
Support Eshell iterative evaluation in the background This really just generalizes Eshell's previous support for iterative evaluation of a single current command to a list of multiple commands, of which at most one can be in the foreground (bug#66066). * lisp/eshell/esh-cmd.el (eshell-last-async-procs) (eshell-current-command): Make obsolete in favor of... (eshell-foreground-command): ... this (eshell-background-commands): New variable. (eshell-interactive-process-p): Make obsolete. (eshell-head-process, eshell-tail-process): Use 'eshell-foreground-command'. (eshell-cmd-initialize): Initialize new variables. (eshell-add-command, eshell-remove-command) (eshell-commands-for-process): New functions. (eshell-parse-command): Make 'eshell-do-subjob' the outermost call. (eshell-do-subjob): Call 'eshell-resume-eval' to split this command off from its parent forms. (eshell-eval-command): Use 'eshell-add-command'. (eshell-resume-command): Use 'eshell-commands-for-process'. (eshell-resume-eval): Take a COMMAND argument. Return ':eshell-background' form for deferred background commands. (eshell-do-eval): Remove check for 'eshell-current-subjob-p'. This is handled differently now. * lisp/eshell/eshell.el (eshell-command): Wait for all processes to exit when running synchronously. * lisp/eshell/esh-mode.el (eshell-intercept-commands) (eshell-watch-for-password-prompt): * lisp/eshell/em-cmpl.el (eshell-complete-parse-arguments): * lisp/eshell/em-smart.el (eshell-smart-display-move): Use 'eshell-foreground-command'. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/background/simple-command) (esh-cmd-test/background/subcommand): New tests. (esh-cmd-test/throw): Use 'eshell-foreground-command'. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Use 'eshell-foreground-command'. * test/lisp/eshell/em-script-tests.el (em-script-test/source-script/background): Make the test script more complex. * test/lisp/eshell/eshell-tests.el (eshell-test/eshell-command/pipeline-wait): New test. * doc/misc/eshell.texi (Bugs and ideas): Remove implemented feature.
2023-09-23 11:36:11 -07:00
;; Background command invocation
(ert-deftest esh-cmd-test/background/simple-command ()
"Test invocation with a simple background command."
(skip-unless (executable-find "echo"))
(eshell-with-temp-buffer bufname ""
(with-temp-eshell
(eshell-match-command-output
(format "*echo hi > #<%s> &" bufname)
(rx bos "[echo" (? ".exe") "] " (+ digit) "\n"))
Support Eshell iterative evaluation in the background This really just generalizes Eshell's previous support for iterative evaluation of a single current command to a list of multiple commands, of which at most one can be in the foreground (bug#66066). * lisp/eshell/esh-cmd.el (eshell-last-async-procs) (eshell-current-command): Make obsolete in favor of... (eshell-foreground-command): ... this (eshell-background-commands): New variable. (eshell-interactive-process-p): Make obsolete. (eshell-head-process, eshell-tail-process): Use 'eshell-foreground-command'. (eshell-cmd-initialize): Initialize new variables. (eshell-add-command, eshell-remove-command) (eshell-commands-for-process): New functions. (eshell-parse-command): Make 'eshell-do-subjob' the outermost call. (eshell-do-subjob): Call 'eshell-resume-eval' to split this command off from its parent forms. (eshell-eval-command): Use 'eshell-add-command'. (eshell-resume-command): Use 'eshell-commands-for-process'. (eshell-resume-eval): Take a COMMAND argument. Return ':eshell-background' form for deferred background commands. (eshell-do-eval): Remove check for 'eshell-current-subjob-p'. This is handled differently now. * lisp/eshell/eshell.el (eshell-command): Wait for all processes to exit when running synchronously. * lisp/eshell/esh-mode.el (eshell-intercept-commands) (eshell-watch-for-password-prompt): * lisp/eshell/em-cmpl.el (eshell-complete-parse-arguments): * lisp/eshell/em-smart.el (eshell-smart-display-move): Use 'eshell-foreground-command'. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/background/simple-command) (esh-cmd-test/background/subcommand): New tests. (esh-cmd-test/throw): Use 'eshell-foreground-command'. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Use 'eshell-foreground-command'. * test/lisp/eshell/em-script-tests.el (em-script-test/source-script/background): Make the test script more complex. * test/lisp/eshell/eshell-tests.el (eshell-test/eshell-command/pipeline-wait): New test. * doc/misc/eshell.texi (Bugs and ideas): Remove implemented feature.
2023-09-23 11:36:11 -07:00
(eshell-wait-for-subprocess t))
(should (equal (buffer-string) "hi\n"))))
(ert-deftest esh-cmd-test/background/subcommand ()
"Test invocation with a background command containing subcommands."
(skip-unless (and (executable-find "echo")
(executable-find "rev")))
(eshell-with-temp-buffer bufname ""
(with-temp-eshell
(eshell-match-command-output
(format "*echo ${*echo hello | rev} > #<%s> &" bufname)
(rx "[echo" (? ".exe") "] " (+ digit) "\n"))
(eshell-wait-for-subprocess t))
(should (equal (buffer-string) "olleh\n"))))
(ert-deftest esh-cmd-test/background/kill ()
"Make sure that a background command that gets killed doesn't emit a prompt."
(skip-unless (executable-find "sleep"))
(let ((background-message (rx bos "[sleep" (? ".exe") "] " (+ digit) "\n")))
(with-temp-eshell
(eshell-match-command-output "*sleep 10 &" background-message)
(kill-process (caar eshell-process-list))
(eshell-wait-for-subprocess t)
;; Ensure we didn't emit another prompt after killing the
;; background process.
(should (eshell-match-output background-message)))))
;; Lisp forms
(ert-deftest esh-cmd-test/quoted-lisp-form ()
"Test parsing of a quoted Lisp form."
(eshell-command-result-equal "echo #'(1 2)" '(1 2)))
(ert-deftest esh-cmd-test/backquoted-lisp-form ()
"Test parsing of a backquoted Lisp form."
(let ((eshell-test-value 42))
(eshell-command-result-equal "echo `(answer ,eshell-test-value)"
'(answer 42))))
(ert-deftest esh-cmd-test/backquoted-lisp-form/splice ()
"Test parsing of a backquoted Lisp form using splicing."
(let ((eshell-test-value '(2 3)))
(eshell-command-result-equal "echo `(1 ,@eshell-test-value)"
'(1 2 3))))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;; Logical operators
(ert-deftest esh-cmd-test/and-operator ()
"Test logical && operator."
(skip-unless (executable-find "["))
(with-temp-eshell
(eshell-match-command-output "[ foo = foo ] && echo hi"
"hi\n")
(eshell-match-command-output "[ foo = bar ] && echo hi"
"\\`\\'")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/or-operator ()
"Test logical || operator."
(skip-unless (executable-find "["))
(with-temp-eshell
(eshell-match-command-output "[ foo = foo ] || echo hi"
"\\`\\'")
(eshell-match-command-output "[ foo = bar ] || echo hi"
"hi\n")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;; Pipelines
(ert-deftest esh-cmd-test/pipeline-wait/head-proc ()
"Check that piping a non-process to a process command waits for the process."
(skip-unless (executable-find "cat"))
(with-temp-eshell
(eshell-match-command-output "echo hi | *cat"
"hi")))
(ert-deftest esh-cmd-test/pipeline-wait/tail-proc ()
"Check that piping a process to a non-process command waits for the process."
(skip-unless (executable-find "echo"))
(with-temp-eshell
(eshell-match-command-output "*echo hi | echo bye"
"bye\nhi\n")))
(ert-deftest esh-cmd-test/pipeline-wait/multi-proc ()
"Check that a pipeline waits for all its processes before returning."
(skip-unless (and (executable-find "echo")
(executable-find "sh")
(executable-find "rev")))
(with-temp-eshell
(eshell-match-command-output
"*echo hello | sh -c 'sleep 1; rev' 1>&2 | *echo goodbye"
"goodbye\nolleh\n")))
(ert-deftest esh-cmd-test/pipeline-wait/subcommand ()
"Check that piping with an asynchronous subcommand waits for the subcommand."
(skip-unless (and (executable-find "echo")
(executable-find "cat")))
(with-temp-eshell
(eshell-match-command-output "echo ${*echo hi} | *cat"
"hi")))
(ert-deftest esh-cmd-test/pipeline-wait/subcommand-with-pipe ()
"Check that piping with an asynchronous subcommand with its own pipe works.
This should also wait for the subcommand."
(skip-unless (and (executable-find "echo")
(executable-find "cat")))
(with-temp-eshell
(eshell-match-command-output "echo ${*echo hi | *cat} | *cat"
"hi")))
(ert-deftest esh-cmd-test/pipeline-wait/nested-pipes ()
"Check that piping a subcommand with its own pipe works.
This should also wait for the subcommand."
(skip-unless (and (executable-find "echo")
(executable-find "cat")
(executable-find "sh")
(executable-find "sleep")))
(with-temp-eshell
(eshell-match-command-output
"{ sh -c 'sleep 1; echo goodbye 1>&2' | *echo hello } | *cat"
"hello\ngoodbye\n")))
(ert-deftest esh-cmd-test/reset-in-pipeline/subcommand ()
"Check that subcommands reset `eshell-in-pipeline-p'."
(skip-unless (executable-find "cat"))
(dolist (template '("echo {%s} | *cat"
"echo ${%s} | *cat"
"*cat $<%s> | *cat"))
(eshell-command-result-equal
(format template "echo $eshell-in-pipeline-p")
nil)
(eshell-command-result-equal
(format template "echo | echo $eshell-in-pipeline-p")
"last")
(eshell-command-result-equal
(format template "echo $eshell-in-pipeline-p | echo")
"first")
(eshell-command-result-equal
(format template "echo | echo $eshell-in-pipeline-p | echo")
"t")))
(ert-deftest esh-cmd-test/reset-in-pipeline/lisp ()
"Check that interpolated Lisp forms reset `eshell-in-pipeline-p'."
(skip-unless (executable-find "cat"))
(dolist (template '("echo (%s) | *cat"
"echo $(%s) | *cat"))
(eshell-command-result-equal
(format template "format \"%s\" eshell-in-pipeline-p")
"nil")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;; Control flow statements
(ert-deftest esh-cmd-test/for-loop ()
"Test invocation of a for loop."
(with-temp-eshell
(eshell-match-command-output "for i in 5 { echo $i }"
"5\n")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/for-loop-list ()
"Test invocation of a for loop iterating over a list."
(with-temp-eshell
(eshell-match-command-output "for i in (list 1 2 (list 3 4)) { echo $i }"
"1\n2\n(3 4)\n")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/for-loop-multiple-args ()
"Test invocation of a for loop iterating over multiple arguments."
(with-temp-eshell
(eshell-match-command-output "for i in 1 2 (list 3 4) { echo $i }"
"1\n2\n3\n4\n")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/for-loop-name () ; bug#15231
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
"Test invocation of a for loop using `name'."
(let ((process-environment (cons "name" process-environment)))
(eshell-command-result-equal "for name in 3 { echo $name }"
3)))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/for-loop-name-shadow () ; bug#15372
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
"Test invocation of a for loop using an env-var."
(let ((process-environment (cons "name=env-value" process-environment)))
(with-temp-eshell
(eshell-match-command-output
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
"echo $name; for name in 3 { echo $name }; echo $name"
"env-value\n3\nenv-value\n"))))
(ert-deftest esh-cmd-test/for-loop-for-items-shadow ()
"Test that the variable `for-items' isn't shadowed inside for loops."
(with-temp-eshell
(with-no-warnings (setq-local for-items "hello"))
(eshell-match-command-output "for i in 1 { echo $for-items }"
"hello\n")))
Fix reference-counting of Eshell I/O handles This ensures that output targets in Eshell are only closed when Eshell is actually done with them. In particular, this means that "{ echo foo; echo bar } | rev" prints "raboof" as expected (bug#59545). * lisp/eshell/esh-io.el (eshell-create-handles): Structure the handles differently so the targets and their ref-count can be shared. (eshell-duplicate-handles): Reimplement this to share targets between the original and new handle sets. Add STEAL-P argument. (eshell-protect-handles, eshell-copy-output-handle) (eshell-interactive-output-p, eshell-output-object): Account for changes to the handle structure. (eshell-close-handle): New function... (eshell-close-handles, eshell-set-output-handle): ... use it. (eshell-get-targets): Remove. This only existed to make the previous implementation of 'eshell-duplicate-handles' work. * lisp/eshell/esh-cmd.el (eshell-with-copied-handles): New argument STEAL-P. (eshell-do-pipelines): Use STEAL-P for the last item in the pipeline. (eshell-parse-command): Don't copy handles for the last command in the list; explain why we can't use STEAL-P here. (eshell-eval-command): When queuing input, set 'eshell-command-body' and 'eshell-test-body' for the 'if' conditional (see 'eshell-do-eval'). * test/lisp/eshell/esh-io-tests.el (esh-io-test/redirect-pipe): Split into... (esh-io-test/pipeline/default, esh-io-test/pipeline/all): ... these. (esh-io-test/pipeline/subcommands): New test. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-pipe) (esh-cmd-test/while-loop-pipe, esh-cmd-test/if-statement-pipe) esh-cmd-test/if-else-statement-pipe): New tests. (esh-cmd-test/while-loop): Use 'pop' to simplify the test a bit. * test/lisp/eshell/eshell-test-helpers.el (eshell-test--max-subprocess-time): Rename to... (eshell-test--max-wait-time): ... this. (eshell-wait-for): New function... (eshell-wait-for-subprocess): ... use it. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Fix this test. Previously, it didn't correctly verify that the original command completed. * test/lisp/eshell/em-tramp-tests.el (em-tramp-test/should-replace-command): New macro... (em-tramp-test/su-default, em-tramp-test/su-user) (em-tramp-test/su-login, em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell, em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): ... use it.
2022-12-24 14:31:50 -08:00
(ert-deftest esh-cmd-test/for-loop-pipe ()
"Test invocation of a for loop piped to another command."
(skip-unless (executable-find "rev"))
(with-temp-eshell
(eshell-match-command-output "for i in foo bar baz { echo $i } | rev"
"zabraboof")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/while-loop ()
"Test invocation of a while loop."
(with-temp-eshell
(let ((eshell-test-value '(0 1 2)))
(eshell-match-command-output
(concat "while $eshell-test-value "
Fix reference-counting of Eshell I/O handles This ensures that output targets in Eshell are only closed when Eshell is actually done with them. In particular, this means that "{ echo foo; echo bar } | rev" prints "raboof" as expected (bug#59545). * lisp/eshell/esh-io.el (eshell-create-handles): Structure the handles differently so the targets and their ref-count can be shared. (eshell-duplicate-handles): Reimplement this to share targets between the original and new handle sets. Add STEAL-P argument. (eshell-protect-handles, eshell-copy-output-handle) (eshell-interactive-output-p, eshell-output-object): Account for changes to the handle structure. (eshell-close-handle): New function... (eshell-close-handles, eshell-set-output-handle): ... use it. (eshell-get-targets): Remove. This only existed to make the previous implementation of 'eshell-duplicate-handles' work. * lisp/eshell/esh-cmd.el (eshell-with-copied-handles): New argument STEAL-P. (eshell-do-pipelines): Use STEAL-P for the last item in the pipeline. (eshell-parse-command): Don't copy handles for the last command in the list; explain why we can't use STEAL-P here. (eshell-eval-command): When queuing input, set 'eshell-command-body' and 'eshell-test-body' for the 'if' conditional (see 'eshell-do-eval'). * test/lisp/eshell/esh-io-tests.el (esh-io-test/redirect-pipe): Split into... (esh-io-test/pipeline/default, esh-io-test/pipeline/all): ... these. (esh-io-test/pipeline/subcommands): New test. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-pipe) (esh-cmd-test/while-loop-pipe, esh-cmd-test/if-statement-pipe) esh-cmd-test/if-else-statement-pipe): New tests. (esh-cmd-test/while-loop): Use 'pop' to simplify the test a bit. * test/lisp/eshell/eshell-test-helpers.el (eshell-test--max-subprocess-time): Rename to... (eshell-test--max-wait-time): ... this. (eshell-wait-for): New function... (eshell-wait-for-subprocess): ... use it. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Fix this test. Previously, it didn't correctly verify that the original command completed. * test/lisp/eshell/em-tramp-tests.el (em-tramp-test/should-replace-command): New macro... (em-tramp-test/su-default, em-tramp-test/su-user) (em-tramp-test/su-login, em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell, em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): ... use it.
2022-12-24 14:31:50 -08:00
"{ (pop eshell-test-value) }")
"0\n1\n2\n"))))
(ert-deftest esh-cmd-test/while-loop-lisp-form ()
"Test invocation of a while loop using a Lisp form."
(with-temp-eshell
(let ((eshell-test-value 0))
(eshell-match-command-output
(concat "while (/= eshell-test-value 3) "
"{ setq eshell-test-value (1+ eshell-test-value) }")
"1\n2\n3\n"))))
(ert-deftest esh-cmd-test/while-loop-ext-cmd ()
"Test invocation of a while loop using an external command."
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(skip-unless (executable-find "["))
(with-temp-eshell
(let ((eshell-test-value 0))
(eshell-match-command-output
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(concat "while {[ $eshell-test-value -ne 3 ]} "
"{ setq eshell-test-value (1+ eshell-test-value) }")
"1\n2\n3\n"))))
Fix reference-counting of Eshell I/O handles This ensures that output targets in Eshell are only closed when Eshell is actually done with them. In particular, this means that "{ echo foo; echo bar } | rev" prints "raboof" as expected (bug#59545). * lisp/eshell/esh-io.el (eshell-create-handles): Structure the handles differently so the targets and their ref-count can be shared. (eshell-duplicate-handles): Reimplement this to share targets between the original and new handle sets. Add STEAL-P argument. (eshell-protect-handles, eshell-copy-output-handle) (eshell-interactive-output-p, eshell-output-object): Account for changes to the handle structure. (eshell-close-handle): New function... (eshell-close-handles, eshell-set-output-handle): ... use it. (eshell-get-targets): Remove. This only existed to make the previous implementation of 'eshell-duplicate-handles' work. * lisp/eshell/esh-cmd.el (eshell-with-copied-handles): New argument STEAL-P. (eshell-do-pipelines): Use STEAL-P for the last item in the pipeline. (eshell-parse-command): Don't copy handles for the last command in the list; explain why we can't use STEAL-P here. (eshell-eval-command): When queuing input, set 'eshell-command-body' and 'eshell-test-body' for the 'if' conditional (see 'eshell-do-eval'). * test/lisp/eshell/esh-io-tests.el (esh-io-test/redirect-pipe): Split into... (esh-io-test/pipeline/default, esh-io-test/pipeline/all): ... these. (esh-io-test/pipeline/subcommands): New test. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-pipe) (esh-cmd-test/while-loop-pipe, esh-cmd-test/if-statement-pipe) esh-cmd-test/if-else-statement-pipe): New tests. (esh-cmd-test/while-loop): Use 'pop' to simplify the test a bit. * test/lisp/eshell/eshell-test-helpers.el (eshell-test--max-subprocess-time): Rename to... (eshell-test--max-wait-time): ... this. (eshell-wait-for): New function... (eshell-wait-for-subprocess): ... use it. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Fix this test. Previously, it didn't correctly verify that the original command completed. * test/lisp/eshell/em-tramp-tests.el (em-tramp-test/should-replace-command): New macro... (em-tramp-test/su-default, em-tramp-test/su-user) (em-tramp-test/su-login, em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell, em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): ... use it.
2022-12-24 14:31:50 -08:00
(ert-deftest esh-cmd-test/while-loop-pipe ()
"Test invocation of a while loop piped to another command."
(skip-unless (executable-find "rev"))
(with-temp-eshell
(let ((eshell-test-value '("foo" "bar" "baz")))
(eshell-match-command-output
(concat "while $eshell-test-value "
"{ (pop eshell-test-value) }"
" | rev")
"zabraboof"))))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/until-loop ()
"Test invocation of an until loop."
(with-temp-eshell
(let ((eshell-test-value nil))
(eshell-match-command-output
(concat "until $eshell-test-value "
"{ setq eshell-test-value t }")
"t\n"))))
(ert-deftest esh-cmd-test/until-loop-lisp-form ()
"Test invocation of an until loop using a Lisp form."
(skip-unless (executable-find "["))
(with-temp-eshell
(let ((eshell-test-value 0))
(eshell-match-command-output
(concat "until (= eshell-test-value 3) "
"{ setq eshell-test-value (1+ eshell-test-value) }")
"1\n2\n3\n"))))
(ert-deftest esh-cmd-test/until-loop-ext-cmd ()
"Test invocation of an until loop using an external command."
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(skip-unless (executable-find "["))
(with-temp-eshell
(let ((eshell-test-value 0))
(eshell-match-command-output
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(concat "until {[ $eshell-test-value -eq 3 ]} "
"{ setq eshell-test-value (1+ eshell-test-value) }")
"1\n2\n3\n"))))
(ert-deftest esh-cmd-test/if-statement ()
"Test invocation of an if statement."
(let ((eshell-test-value t))
(eshell-command-result-equal "if $eshell-test-value {echo yes}"
"yes"))
(let ((eshell-test-value nil))
(eshell-command-result-equal "if $eshell-test-value {echo yes}"
nil)))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/if-else-statement ()
"Test invocation of an if/else statement."
(let ((eshell-test-value t))
(eshell-command-result-equal "if $eshell-test-value {echo yes} {echo no}"
"yes"))
(let ((eshell-test-value nil))
(eshell-command-result-equal "if $eshell-test-value {echo yes} {echo no}"
"no")))
(ert-deftest esh-cmd-test/if-else-statement-lisp-form ()
"Test invocation of an if/else statement using a Lisp form."
(eshell-command-result-equal "if (zerop 0) {echo yes} {echo no}"
"yes")
(eshell-command-result-equal "if (zerop 1) {echo yes} {echo no}"
"no")
(let ((debug-on-error nil))
(eshell-command-result-equal "if (zerop \"foo\") {echo yes} {echo no}"
"no")))
(ert-deftest esh-cmd-test/if-else-statement-lisp-form-2 ()
"Test invocation of an if/else statement using a Lisp form.
This tests when `eshell-lisp-form-nil-is-failure' is nil."
(let ((eshell-lisp-form-nil-is-failure nil))
(eshell-command-result-equal "if (zerop 0) {echo yes} {echo no}"
"yes")
(eshell-command-result-equal "if (zerop 1) {echo yes} {echo no}"
"yes")
(let ((debug-on-error nil))
(eshell-command-result-equal "if (zerop \"foo\") {echo yes} {echo no}"
"no"))))
(ert-deftest esh-cmd-test/if-else-statement-ext-cmd ()
"Test invocation of an if/else statement using an external command."
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(skip-unless (executable-find "["))
(eshell-command-result-equal "if {[ foo = foo ]} {echo yes} {echo no}"
"yes")
(eshell-command-result-equal "if {[ foo = bar ]} {echo yes} {echo no}"
"no"))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
Fix reference-counting of Eshell I/O handles This ensures that output targets in Eshell are only closed when Eshell is actually done with them. In particular, this means that "{ echo foo; echo bar } | rev" prints "raboof" as expected (bug#59545). * lisp/eshell/esh-io.el (eshell-create-handles): Structure the handles differently so the targets and their ref-count can be shared. (eshell-duplicate-handles): Reimplement this to share targets between the original and new handle sets. Add STEAL-P argument. (eshell-protect-handles, eshell-copy-output-handle) (eshell-interactive-output-p, eshell-output-object): Account for changes to the handle structure. (eshell-close-handle): New function... (eshell-close-handles, eshell-set-output-handle): ... use it. (eshell-get-targets): Remove. This only existed to make the previous implementation of 'eshell-duplicate-handles' work. * lisp/eshell/esh-cmd.el (eshell-with-copied-handles): New argument STEAL-P. (eshell-do-pipelines): Use STEAL-P for the last item in the pipeline. (eshell-parse-command): Don't copy handles for the last command in the list; explain why we can't use STEAL-P here. (eshell-eval-command): When queuing input, set 'eshell-command-body' and 'eshell-test-body' for the 'if' conditional (see 'eshell-do-eval'). * test/lisp/eshell/esh-io-tests.el (esh-io-test/redirect-pipe): Split into... (esh-io-test/pipeline/default, esh-io-test/pipeline/all): ... these. (esh-io-test/pipeline/subcommands): New test. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-pipe) (esh-cmd-test/while-loop-pipe, esh-cmd-test/if-statement-pipe) esh-cmd-test/if-else-statement-pipe): New tests. (esh-cmd-test/while-loop): Use 'pop' to simplify the test a bit. * test/lisp/eshell/eshell-test-helpers.el (eshell-test--max-subprocess-time): Rename to... (eshell-test--max-wait-time): ... this. (eshell-wait-for): New function... (eshell-wait-for-subprocess): ... use it. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Fix this test. Previously, it didn't correctly verify that the original command completed. * test/lisp/eshell/em-tramp-tests.el (em-tramp-test/should-replace-command): New macro... (em-tramp-test/su-default, em-tramp-test/su-user) (em-tramp-test/su-login, em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell, em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): ... use it.
2022-12-24 14:31:50 -08:00
(ert-deftest esh-cmd-test/if-statement-pipe ()
"Test invocation of an if statement piped to another command."
(skip-unless (executable-find "rev"))
(with-temp-eshell
(let ((eshell-test-value t))
(eshell-match-command-output "if $eshell-test-value {echo yes} | rev"
"\\`sey\n?"))
(let ((eshell-test-value nil))
(eshell-match-command-output "if $eshell-test-value {echo yes} | rev"
"\\`\n?"))))
Fix reference-counting of Eshell I/O handles This ensures that output targets in Eshell are only closed when Eshell is actually done with them. In particular, this means that "{ echo foo; echo bar } | rev" prints "raboof" as expected (bug#59545). * lisp/eshell/esh-io.el (eshell-create-handles): Structure the handles differently so the targets and their ref-count can be shared. (eshell-duplicate-handles): Reimplement this to share targets between the original and new handle sets. Add STEAL-P argument. (eshell-protect-handles, eshell-copy-output-handle) (eshell-interactive-output-p, eshell-output-object): Account for changes to the handle structure. (eshell-close-handle): New function... (eshell-close-handles, eshell-set-output-handle): ... use it. (eshell-get-targets): Remove. This only existed to make the previous implementation of 'eshell-duplicate-handles' work. * lisp/eshell/esh-cmd.el (eshell-with-copied-handles): New argument STEAL-P. (eshell-do-pipelines): Use STEAL-P for the last item in the pipeline. (eshell-parse-command): Don't copy handles for the last command in the list; explain why we can't use STEAL-P here. (eshell-eval-command): When queuing input, set 'eshell-command-body' and 'eshell-test-body' for the 'if' conditional (see 'eshell-do-eval'). * test/lisp/eshell/esh-io-tests.el (esh-io-test/redirect-pipe): Split into... (esh-io-test/pipeline/default, esh-io-test/pipeline/all): ... these. (esh-io-test/pipeline/subcommands): New test. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-pipe) (esh-cmd-test/while-loop-pipe, esh-cmd-test/if-statement-pipe) esh-cmd-test/if-else-statement-pipe): New tests. (esh-cmd-test/while-loop): Use 'pop' to simplify the test a bit. * test/lisp/eshell/eshell-test-helpers.el (eshell-test--max-subprocess-time): Rename to... (eshell-test--max-wait-time): ... this. (eshell-wait-for): New function... (eshell-wait-for-subprocess): ... use it. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Fix this test. Previously, it didn't correctly verify that the original command completed. * test/lisp/eshell/em-tramp-tests.el (em-tramp-test/should-replace-command): New macro... (em-tramp-test/su-default, em-tramp-test/su-user) (em-tramp-test/su-login, em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell, em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): ... use it.
2022-12-24 14:31:50 -08:00
(ert-deftest esh-cmd-test/if-else-statement-pipe ()
"Test invocation of an if/else statement piped to another command."
(skip-unless (executable-find "rev"))
(with-temp-eshell
(let ((eshell-test-value t))
(eshell-match-command-output
"if $eshell-test-value {echo yes} {echo no} | rev"
"\\`sey\n?"))
(let ((eshell-test-value nil))
(eshell-match-command-output
"if $eshell-test-value {echo yes} {echo no} | rev"
"\\`on\n?"))))
Fix reference-counting of Eshell I/O handles This ensures that output targets in Eshell are only closed when Eshell is actually done with them. In particular, this means that "{ echo foo; echo bar } | rev" prints "raboof" as expected (bug#59545). * lisp/eshell/esh-io.el (eshell-create-handles): Structure the handles differently so the targets and their ref-count can be shared. (eshell-duplicate-handles): Reimplement this to share targets between the original and new handle sets. Add STEAL-P argument. (eshell-protect-handles, eshell-copy-output-handle) (eshell-interactive-output-p, eshell-output-object): Account for changes to the handle structure. (eshell-close-handle): New function... (eshell-close-handles, eshell-set-output-handle): ... use it. (eshell-get-targets): Remove. This only existed to make the previous implementation of 'eshell-duplicate-handles' work. * lisp/eshell/esh-cmd.el (eshell-with-copied-handles): New argument STEAL-P. (eshell-do-pipelines): Use STEAL-P for the last item in the pipeline. (eshell-parse-command): Don't copy handles for the last command in the list; explain why we can't use STEAL-P here. (eshell-eval-command): When queuing input, set 'eshell-command-body' and 'eshell-test-body' for the 'if' conditional (see 'eshell-do-eval'). * test/lisp/eshell/esh-io-tests.el (esh-io-test/redirect-pipe): Split into... (esh-io-test/pipeline/default, esh-io-test/pipeline/all): ... these. (esh-io-test/pipeline/subcommands): New test. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/for-loop-pipe) (esh-cmd-test/while-loop-pipe, esh-cmd-test/if-statement-pipe) esh-cmd-test/if-else-statement-pipe): New tests. (esh-cmd-test/while-loop): Use 'pop' to simplify the test a bit. * test/lisp/eshell/eshell-test-helpers.el (eshell-test--max-subprocess-time): Rename to... (eshell-test--max-wait-time): ... this. (eshell-wait-for): New function... (eshell-wait-for-subprocess): ... use it. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Fix this test. Previously, it didn't correctly verify that the original command completed. * test/lisp/eshell/em-tramp-tests.el (em-tramp-test/should-replace-command): New macro... (em-tramp-test/su-default, em-tramp-test/su-user) (em-tramp-test/su-login, em-tramp-test/sudo-shell) (em-tramp-test/sudo-user-shell, em-tramp-test/doas-shell) (em-tramp-test/doas-user-shell): ... use it.
2022-12-24 14:31:50 -08:00
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/unless-statement ()
"Test invocation of an unless statement."
(let ((eshell-test-value t))
(eshell-command-result-equal "unless $eshell-test-value {echo no}"
nil))
(let ((eshell-test-value nil))
(eshell-command-result-equal "unless $eshell-test-value {echo no}"
"no")))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(ert-deftest esh-cmd-test/unless-else-statement ()
"Test invocation of an unless/else statement."
(let ((eshell-test-value t))
(eshell-command-result-equal
"unless $eshell-test-value {echo no} {echo yes}"
"yes"))
(let ((eshell-test-value nil))
(eshell-command-result-equal
"unless $eshell-test-value {echo no} {echo yes}"
"no")))
(ert-deftest esh-cmd-test/unless-else-statement-lisp-form ()
"Test invocation of an unless/else statement using a Lisp form."
(eshell-command-result-equal "unless (zerop 0) {echo no} {echo yes}"
"yes")
(eshell-command-result-equal "unless (zerop 1) {echo no} {echo yes}"
"no")
(let ((debug-on-error nil))
(eshell-command-result-equal "unless (zerop \"foo\") {echo no} {echo yes}"
"no")))
(ert-deftest esh-cmd-test/unless-else-statement-ext-cmd ()
"Test invocation of an unless/else statement using an external command."
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
(skip-unless (executable-find "["))
(eshell-command-result-equal "unless {[ foo = foo ]} {echo no} {echo yes}"
"yes")
(eshell-command-result-equal "unless {[ foo = bar ]} {echo no} {echo yes}"
"no"))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;; Direct invocation
(defmacro esh-cmd-test--deftest-invoke-directly (name command expected)
"Test `eshell-invoke-directly-p' returns EXPECTED for COMMAND.
NAME is the name of the test case."
(declare (indent 2))
`(ert-deftest ,(intern (concat "esh-cmd-test/invoke-directly/"
(symbol-name name)))
()
(with-temp-eshell
(should (equal (eshell-invoke-directly-p
(eshell-parse-command ,command nil t))
,expected)))))
(esh-cmd-test--deftest-invoke-directly no-args "echo" t)
(esh-cmd-test--deftest-invoke-directly with-args "echo hi" t)
(esh-cmd-test--deftest-invoke-directly multiple-cmds "echo hi; echo bye" nil)
(esh-cmd-test--deftest-invoke-directly subcmd "echo ${echo hi}" t)
(esh-cmd-test--deftest-invoke-directly complex "ls ." nil)
(esh-cmd-test--deftest-invoke-directly complex-subcmd "echo {ls .}" nil)
;; Error handling
(ert-deftest esh-cmd-test/empty-background-command ()
"Test that Eshell reports an error when trying to background a nil command."
(let ((text-quoting-style 'grave))
(with-temp-eshell
(eshell-match-command-output "echo hi & &"
"\\`Empty command before `&'\n")
;; Make sure the next Eshell prompt has the original input so the
;; user can fix it.
(should (equal (buffer-substring eshell-last-output-end (point))
"echo hi & &")))))
(ert-deftest esh-cmd-test/throw ()
"Test that calling `throw' as an Eshell command unwinds everything properly."
(with-temp-eshell
(should (= (catch 'tag
(eshell-insert-command
"echo hi; (throw 'tag 42); echo bye"))
42))
(should (eshell-match-output "\\`hi\n\\'"))
Support Eshell iterative evaluation in the background This really just generalizes Eshell's previous support for iterative evaluation of a single current command to a list of multiple commands, of which at most one can be in the foreground (bug#66066). * lisp/eshell/esh-cmd.el (eshell-last-async-procs) (eshell-current-command): Make obsolete in favor of... (eshell-foreground-command): ... this (eshell-background-commands): New variable. (eshell-interactive-process-p): Make obsolete. (eshell-head-process, eshell-tail-process): Use 'eshell-foreground-command'. (eshell-cmd-initialize): Initialize new variables. (eshell-add-command, eshell-remove-command) (eshell-commands-for-process): New functions. (eshell-parse-command): Make 'eshell-do-subjob' the outermost call. (eshell-do-subjob): Call 'eshell-resume-eval' to split this command off from its parent forms. (eshell-eval-command): Use 'eshell-add-command'. (eshell-resume-command): Use 'eshell-commands-for-process'. (eshell-resume-eval): Take a COMMAND argument. Return ':eshell-background' form for deferred background commands. (eshell-do-eval): Remove check for 'eshell-current-subjob-p'. This is handled differently now. * lisp/eshell/eshell.el (eshell-command): Wait for all processes to exit when running synchronously. * lisp/eshell/esh-mode.el (eshell-intercept-commands) (eshell-watch-for-password-prompt): * lisp/eshell/em-cmpl.el (eshell-complete-parse-arguments): * lisp/eshell/em-smart.el (eshell-smart-display-move): Use 'eshell-foreground-command'. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/background/simple-command) (esh-cmd-test/background/subcommand): New tests. (esh-cmd-test/throw): Use 'eshell-foreground-command'. * test/lisp/eshell/eshell-tests.el (eshell-test/queue-input): Use 'eshell-foreground-command'. * test/lisp/eshell/em-script-tests.el (em-script-test/source-script/background): Make the test script more complex. * test/lisp/eshell/eshell-tests.el (eshell-test/eshell-command/pipeline-wait): New test. * doc/misc/eshell.texi (Bugs and ideas): Remove implemented feature.
2023-09-23 11:36:11 -07:00
(should-not eshell-foreground-command)
;; Make sure we can call another command after throwing.
(eshell-match-command-output "echo again" "\\`again\n")))
Make Eshell's "which" command extensible Since 'eshell-named-command-hook' already makes execution of commands extensible, "which" should be too. This makes sure that "which" returns the right result for quoted commands like "/:cat". * lisp/eshell/em-alias.el (eshell-aliases-file): Allow it to be nil. (eshell-read-aliases-list, eshell-write-aliases-list): Check if 'eshell-aliases-file' is nil. (eshell-maybe-replace-by-alias--which): New function... (eshell-maybe-replace-by-alias): ... use it. * lisp/eshell/esh-cmd.el (eshell-named-command-hook): Update docstring. (eshell/which): Make extensible. (eshell--find-plain-lisp-command, eshell-plain-command--which): New functions. (eshell-plain-command): Use 'eshell--find-plain-lisp-command'. * lisp/eshell/esh-ext.el (eshell-explicit-command--which): New function... (eshell-explicit-command): ... unise it. (eshell-quoted-file-command--which): New function... (eshell-quoted-file-command): ... use it. (eshell-external-command--which): New function. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/which/plain/eshell-builtin) (esh-cmd-test/which/plain/external-program) (esh-cmd-test/which/plain/not-found, esh-cmd-test/which/alias) (esh-cmd-test/which/explicit, esh-cmd-test/which/explicit/not-found) (esh-cmd-test/which/quoted-file) (esh-cmd-test/which/quoted-file/not-found): New tests. * test/lisp/eshell/eshell-tests-helpers.el (with-temp-eshell-settings): Don't load or save aliases. (eshell-command-result--match,eshell-command-result--match-explainer) (eshell-command-result-match): New functions.
2024-05-29 19:21:09 -07:00
;; `which' command
(ert-deftest esh-cmd-test/which/plain/eshell-builtin ()
"Check that `which' finds Eshell built-in functions."
(eshell-command-result-match "which cat" "\\`eshell/cat"))
(ert-deftest esh-cmd-test/which/plain/external-program ()
"Check that `which' finds external programs."
(skip-unless (executable-find "sh"))
(ert-info (#'eshell-get-debug-logs :prefix "Command logs: ")
(let ((actual (eshell-test-command-result "which sh"))
(expected (concat (executable-find "sh") "\n")))
;; Eshell handles the casing of the PATH differently from
;; `executable-find'. This means that the results may not match
;; exactly on case-insensitive file systems (e.g. when using
;; MS-Windows), so compare case-insensitively there.
(should (if (file-name-case-insensitive-p actual)
(string-equal-ignore-case actual expected)
(string-equal actual expected))))))
Make Eshell's "which" command extensible Since 'eshell-named-command-hook' already makes execution of commands extensible, "which" should be too. This makes sure that "which" returns the right result for quoted commands like "/:cat". * lisp/eshell/em-alias.el (eshell-aliases-file): Allow it to be nil. (eshell-read-aliases-list, eshell-write-aliases-list): Check if 'eshell-aliases-file' is nil. (eshell-maybe-replace-by-alias--which): New function... (eshell-maybe-replace-by-alias): ... use it. * lisp/eshell/esh-cmd.el (eshell-named-command-hook): Update docstring. (eshell/which): Make extensible. (eshell--find-plain-lisp-command, eshell-plain-command--which): New functions. (eshell-plain-command): Use 'eshell--find-plain-lisp-command'. * lisp/eshell/esh-ext.el (eshell-explicit-command--which): New function... (eshell-explicit-command): ... unise it. (eshell-quoted-file-command--which): New function... (eshell-quoted-file-command): ... use it. (eshell-external-command--which): New function. * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/which/plain/eshell-builtin) (esh-cmd-test/which/plain/external-program) (esh-cmd-test/which/plain/not-found, esh-cmd-test/which/alias) (esh-cmd-test/which/explicit, esh-cmd-test/which/explicit/not-found) (esh-cmd-test/which/quoted-file) (esh-cmd-test/which/quoted-file/not-found): New tests. * test/lisp/eshell/eshell-tests-helpers.el (with-temp-eshell-settings): Don't load or save aliases. (eshell-command-result--match,eshell-command-result--match-explainer) (eshell-command-result-match): New functions.
2024-05-29 19:21:09 -07:00
(ert-deftest esh-cmd-test/which/plain/not-found ()
"Check that `which' reports an error for not-found commands."
(skip-when (executable-find "nonexist"))
(eshell-command-result-match "which nonexist" "\\`which: no nonexist in"))
(ert-deftest esh-cmd-test/which/alias ()
"Check that `which' finds aliases."
(with-temp-eshell
(eshell-insert-command "alias cat '*cat $@*'")
(eshell-match-command-output "which cat" "\\`cat is an alias")))
(ert-deftest esh-cmd-test/which/explicit ()
"Check that `which' finds explicitly-external programs."
(skip-unless (executable-find "cat"))
(eshell-command-result-match "which *cat"
(concat (executable-find "cat") "\n")))
(ert-deftest esh-cmd-test/which/explicit/not-found ()
"Check that `which' reports an error for not-found explicit commands."
(skip-when (executable-find "nonexist"))
(eshell-command-result-match "which *nonexist" "\\`which: no nonexist in"))
(ert-deftest esh-cmd-test/which/quoted-file ()
"Check that `which' finds programs with quoted file names."
(skip-unless (executable-find "cat"))
(eshell-command-result-match "which /:cat"
(concat (executable-find "cat") "\n")))
(ert-deftest esh-cmd-test/which/quoted-file/not-found ()
"Check that `which' reports an error for not-found quoted commands."
(skip-when (executable-find "nonexist"))
(eshell-command-result-match "which /:nonexist" "\\`which: no nonexist in"))
Only set Eshell execution result metavariables when non-nil This simplifies usage of 'eshell-close-handles' in several places and makes it work more like the docstring indicated it would. * lisp/eshell/esh-io.el (eshell-close-handles): Only store EXIT-CODE and RESULT if they're non-nil. Also, use 'dotimes' and 'dolist' to simplify the implementation. * lisp/eshell/em-alias.el (eshell-write-aliases-list): * lisp/eshell/esh-cmd.el (eshell-rewrite-for-command) (eshell-structure-basic-command): Adapt calls to 'eshell-close-handles'. * test/lisp/eshell/eshell-tests.el (eshell-test/simple-command-result) (eshell-test/lisp-command, eshell-test/lisp-command-with-quote) (eshell-test/for-loop, eshell-test/for-name-loop) (eshell-test/for-name-shadow-loop, eshell-test/lisp-command-args) (eshell-test/subcommand, eshell-test/subcommand-args) (eshell-test/subcommand-lisp): Move from here... * test/lisp/eshell/esh-cmd-tests.el (esh-cmd-test/simple-command-result, esh-cmd-test/lisp-command) (esh-cmd-test/lisp-command-with-quote, esh-cmd-test/for-loop) (esh-cmd-test/for-name-loop, esh-cmd-test/for-name-shadow-loop) (esh-cmd-test/lisp-command-args, esh-cmd-test/subcommand) (esh-cmd-test/subcommand-args, esh-cmd-test/subcommand-lisp): ... to here. (esh-cmd-test/and-operator, esh-cmd-test/or-operator) (esh-cmd-test/for-loop-list, esh-cmd-test/for-loop-multiple-args) (esh-cmd-test/while-loop, esh-cmd-test/until-loop) (esh-cmd-test/if-statement, esh-cmd-test/if-else-statement) (esh-cmd-test/unless-statement, esh-cmd-test/unless-else-statement): New tests. * doc/misc/eshell.texi (Invocation): Explain '&&' and '||'. (for loop): Move from here... (Control Flow): ... to here, and add documentation for other control flow forms.
2022-08-06 13:37:28 -07:00
;; esh-cmd-tests.el ends here