summaryrefslogtreecommitdiff
path: root/test/lisp/eshell/esh-cmd-tests.el
diff options
context:
space:
mode:
Diffstat (limited to 'test/lisp/eshell/esh-cmd-tests.el')
-rw-r--r--test/lisp/eshell/esh-cmd-tests.el222
1 files changed, 218 insertions, 4 deletions
diff --git a/test/lisp/eshell/esh-cmd-tests.el b/test/lisp/eshell/esh-cmd-tests.el
index 4ee2c5bcb0e..ef965a896c1 100644
--- a/test/lisp/eshell/esh-cmd-tests.el
+++ b/test/lisp/eshell/esh-cmd-tests.el
@@ -73,6 +73,62 @@ Test that trailing arguments outside the subcommand are ignored.
e.g. \"{(+ 1 2)} 3\" => 3"
(eshell-command-result-equal "{(+ 1 2)} 3" 3))
+(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")))
+
+
+;; 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 "[echo" (? ".exe") "] " (+ digit) "\n"))
+ (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"))))
+
;; Lisp forms
@@ -114,6 +170,78 @@ e.g. \"{(+ 1 2)} 3\" => 3"
"hi\n")))
+;; 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/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")))
+
+
;; Control flow statements
(ert-deftest esh-cmd-test/for-loop ()
@@ -134,13 +262,13 @@ e.g. \"{(+ 1 2)} 3\" => 3"
(eshell-match-command-output "for i in 1 2 (list 3 4) { echo $i }"
"1\n2\n3\n4\n")))
-(ert-deftest esh-cmd-test/for-name-loop () ; bug#15231
+(ert-deftest esh-cmd-test/for-loop-name () ; bug#15231
"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)))
-(ert-deftest esh-cmd-test/for-name-shadow-loop () ; bug#15372
+(ert-deftest esh-cmd-test/for-loop-name-shadow () ; bug#15372
"Test invocation of a for loop using an env-var."
(let ((process-environment (cons "name=env-value" process-environment)))
(with-temp-eshell
@@ -148,14 +276,28 @@ e.g. \"{(+ 1 2)} 3\" => 3"
"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")))
+
+(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")))
+
(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 "
- "{ setq eshell-test-value (cdr eshell-test-value) }")
- "(1 2)\n(2)\n"))))
+ "{ (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."
@@ -176,6 +318,17 @@ e.g. \"{(+ 1 2)} 3\" => 3"
"{ setq eshell-test-value (1+ eshell-test-value) }")
"1\n2\n3\n"))))
+(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"))))
+
(ert-deftest esh-cmd-test/until-loop ()
"Test invocation of an until loop."
(with-temp-eshell
@@ -253,6 +406,30 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil."
(eshell-command-result-equal "if {[ foo = bar ]} {echo yes} {echo no}"
"no"))
+(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?"))))
+
+(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?"))))
+
(ert-deftest esh-cmd-test/unless-statement ()
"Test invocation of an unless statement."
(let ((eshell-test-value t))
@@ -291,4 +468,41 @@ This tests when `eshell-lisp-form-nil-is-failure' is nil."
(eshell-command-result-equal "unless {[ foo = bar ]} {echo no} {echo yes}"
"no"))
+
+;; 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/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\\'"))
+ (should-not eshell-foreground-command)
+ ;; Make sure we can call another command after throwing.
+ (eshell-match-command-output "echo again" "\\`again\n")))
+
;; esh-cmd-tests.el ends here