emacs/test/lisp/eshell/em-prompt-tests.el

240 lines
10 KiB
EmacsLisp
Raw Normal View History

;;; em-prompt-tests.el --- em-prompt test suite -*- lexical-binding:t -*-
2024-01-02 10:30:05 +08:00
;; Copyright (C) 2023-2024 Free Software Foundation, Inc.
;; 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 prompt support.
;;; Code:
(require 'ert)
(require 'eshell)
(require 'em-prompt)
(require 'eshell-tests-helpers
(expand-file-name "eshell-tests-helpers"
(file-name-directory (or load-file-name
default-directory))))
(defmacro em-prompt-test--with-multiline (&rest body)
"Execute BODY with a multiline Eshell prompt."
`(let ((eshell-prompt-function (lambda () "multiline prompt\n$ ")))
,@body))
;;; Tests:
;; Prompt output
(ert-deftest em-prompt-test/field-properties ()
"Check that field properties are properly set on Eshell output/prompts."
(with-temp-eshell
(eshell-insert-command "echo hello")
(let ((last-prompt (field-string (1- eshell-last-input-start)))
(last-input (field-string (1+ eshell-last-input-start)))
(last-output (field-string (1+ eshell-last-input-end))))
(should (equal-including-properties
last-prompt
(propertize
(format "%s %s " (directory-file-name default-directory)
(if (= (file-user-uid) 0) "#" "$"))
'read-only t
'field 'prompt
'font-lock-face 'eshell-prompt
'front-sticky '(read-only field font-lock-face)
'rear-nonsticky '(read-only field font-lock-face))))
(should (equal last-input "echo hello\n"))
(should (equal-including-properties
last-output
(apply #'propertize "hello\n"
eshell-command-output-properties))))))
(ert-deftest em-prompt-test/field-properties/no-highlight ()
"Check that field properties are properly set on Eshell output/prompts.
This tests the case when `eshell-highlight-prompt' is nil."
(let ((eshell-highlight-prompt nil))
(with-temp-eshell
(eshell-insert-command "echo hello")
(let ((last-prompt (field-string (1- eshell-last-input-start)))
(last-input (field-string (1+ eshell-last-input-start)))
(last-output (field-string (1+ eshell-last-input-end))))
(should (equal-including-properties
last-prompt
(propertize
(format "%s %s " (directory-file-name default-directory)
(if (= (file-user-uid) 0) "#" "$"))
'field 'prompt
'front-sticky '(field)
'rear-nonsticky '(field))))
(should (equal last-input "echo hello\n"))
(should (equal-including-properties
last-output
(apply #'propertize "hello\n"
eshell-command-output-properties)))))))
(ert-deftest em-prompt-test/after-failure ()
"Check that current prompt shows the exit code of the last failed command."
(with-temp-eshell
(let ((debug-on-error nil))
(eshell-insert-command "(zerop \"foo\")"))
(let ((current-prompt (field-string (1- (point)))))
(should (equal-including-properties
current-prompt
(propertize
(concat (directory-file-name default-directory)
(unless (eshell-exit-success-p)
(format " [%d]" eshell-last-command-status))
(if (= (file-user-uid) 0) " # " " $ "))
'read-only t
'field 'prompt
'font-lock-face 'eshell-prompt
'front-sticky '(read-only field font-lock-face)
'rear-nonsticky '(read-only field font-lock-face)))))))
;; Prompt navigation
(defun em-prompt-test/next-previous-prompt-1 ()
"Helper for checking forward/backward navigation of old prompts."
(with-temp-eshell
(eshell-insert-command "echo one")
(eshell-insert-command "echo two")
(eshell-insert-command "echo three")
(let ((debug-on-error nil)) ; A failed command.
(eshell-insert-command "(zerop \"foo\")"))
(insert "echo fou") ; A partially-entered command.
(ert-info ("Go back one prompt")
(eshell-previous-prompt)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "(zerop \"foo\")\n")))
(ert-info ("Go back three prompts, starting from the end of the input")
(end-of-line)
(eshell-previous-prompt 3)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo one\n")))
(ert-info ("Go to the current prompt, starting from the end of the input")
(end-of-line)
(eshell-previous-prompt 0)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo one\n")))
(ert-info ("Go forward one prompt")
(eshell-next-prompt)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo two\n")))
(ert-info ("Go forward three prompts")
(eshell-next-prompt 3)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo fou")))
(ert-info ("Go back one prompt, starting from the beginning of the line")
(forward-line 0)
(eshell-previous-prompt 1)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "(zerop \"foo\")\n")))
(ert-info ("Go back one prompt, starting from the previous prompt's output")
(forward-line -1)
(eshell-previous-prompt 1)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo three\n")))))
(ert-deftest em-prompt-test/next-previous-prompt ()
"Check that navigating forward/backward through old prompts works correctly."
(em-prompt-test/next-previous-prompt-1))
(ert-deftest em-prompt-test/next-previous-prompt/multiline ()
"Check old prompt forward/backward navigation for multiline prompts."
(em-prompt-test--with-multiline
(em-prompt-test/next-previous-prompt-1)))
(defun em-prompt-test/forward-backward-paragraph-1 ()
"Helper for checking forward/backward navigation by paragraphs."
(with-temp-eshell
(cl-flet ((at-prompt-for-command-p (command)
(and (equal (point) (field-beginning))
(equal (get-text-property (point) 'field) 'prompt)
(save-excursion
(goto-char (field-end))
(equal (field-string) command)))))
(eshell-insert-command "echo 'high five'")
(eshell-insert-command "echo 'up high\n\ndown low'")
(eshell-insert-command "echo 'too slow'")
(insert "echo goodby") ; A partially-entered command.
(ert-info ("Go back to the last prompt")
(eshell-backward-paragraph)
(should (at-prompt-for-command-p "echo goodby")))
(ert-info ("Go back to the paragraph break")
(eshell-backward-paragraph 2)
(should (looking-at "\ndown low\n")))
(ert-info ("Go forward to the third prompt")
(eshell-forward-paragraph)
(should (at-prompt-for-command-p "echo 'too slow'\n")))
(ert-info ("Go backward to before the first prompt")
(eshell-backward-paragraph 5)
(should (looking-back "Welcome to the Emacs shell\n")))
(ert-info ("Go backward to the beginning of the buffer")
(eshell-backward-paragraph)
(should (bobp)))
(ert-info ("Go forward to the second prompt")
(eshell-forward-paragraph 3)
(should (at-prompt-for-command-p "echo 'up high\n\ndown low'\n"))))))
(ert-deftest em-prompt-test/forward-backward-paragraph ()
"Check that navigating forward/backward through paragraphs works correctly."
(em-prompt-test/forward-backward-paragraph-1))
(ert-deftest em-prompt-test/forward-backward-paragraph/multiline ()
"Check paragraph forward/backward navigation for multiline prompts."
(em-prompt-test--with-multiline
(em-prompt-test/forward-backward-paragraph-1)))
(defun em-prompt-test/forward-backward-matching-input-1 ()
"Helper for checking forward/backward navigation via regexps."
(with-temp-eshell
(eshell-insert-command "echo one")
(eshell-insert-command "printnl something else")
(eshell-insert-command "echo two")
(eshell-insert-command "echo three")
(let ((debug-on-error nil)) ; A failed command.
(eshell-insert-command "(zerop \"foo\")"))
(insert "echo fou") ; A partially-entered command.
(ert-info ("Search for \"echo\", back one prompt")
(eshell-backward-matching-input "echo" 1)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo three\n")))
(ert-info ((concat "Search for \"echo\", back two prompts, "
"starting from the end of this line"))
(end-of-line)
(eshell-backward-matching-input "echo" 2)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo one\n")))
(ert-info ("Search for \"echo\", forward three prompts")
(eshell-forward-matching-input "echo" 3)
(should (equal (point) (field-beginning)))
(should (equal (field-string) "echo fou")))))
(ert-deftest em-prompt-test/forward-backward-matching-input ()
"Check that navigating forward/backward via regexps works correctly."
(em-prompt-test/forward-backward-matching-input-1))
(ert-deftest em-prompt-test/forward-backward-matching-input-multiline ()
"Check forward/backward regexp navigation for multiline prompts."
(em-prompt-test--with-multiline
(em-prompt-test/forward-backward-matching-input-1)))
;;; em-prompt-tests.el ends here