diff options
Diffstat (limited to 'test/lisp/files-tests.el')
-rw-r--r-- | test/lisp/files-tests.el | 217 |
1 files changed, 209 insertions, 8 deletions
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el index 2c1fff06f70..718ecd51f8b 100644 --- a/test/lisp/files-tests.el +++ b/test/lisp/files-tests.el @@ -166,6 +166,27 @@ form.") (hack-local-variables) (should (eq lexical-binding nil))))) +(ert-deftest files-tests-safe-local-variable-directories () + ;; safe-local-variable-directories should be risky, + ;; so use it as an arbitrary risky variable. + (let ((test-alist '((safe-local-variable-directories . "some_val"))) + (fakedir default-directory) + (enable-local-eval t)) + (with-temp-buffer + (setq safe-local-variable-directories (list fakedir)) + (hack-local-variables-filter test-alist fakedir) + (should (equal file-local-variables-alist test-alist))) + (with-temp-buffer + (setq safe-local-variable-directories (list fakedir)) + (setq noninteractive t) + (hack-local-variables-filter test-alist "wrong") + (should-not (equal file-local-variables-alist test-alist))) + (with-temp-buffer + (setq safe-local-variable-directories '()) + (setq noninteractive t) + (hack-local-variables-filter test-alist fakedir) + (should-not (equal file-local-variables-alist test-alist))))) + (defvar files-test-bug-18141-file (ert-resource-file "files-bug18141.el.gz") "Test file for bug#18141.") @@ -1201,30 +1222,30 @@ unquoted file names." (let ((process-environment (cons "FOO=foo" process-environment)) (nospecial-foo (files-tests--new-name nospecial "$FOO"))) ;; The "/:" prevents substitution. - (equal (substitute-in-file-name nospecial-foo) nospecial-foo))) + (should (equal (substitute-in-file-name nospecial-foo) nospecial-foo)))) (files-tests--with-temp-non-special-and-file-name-handler (tmpfile nospecial) (let ((process-environment (cons "FOO=foo" process-environment)) (nospecial-foo (files-tests--new-name nospecial "$FOO"))) ;; The "/:" prevents substitution. - (equal (substitute-in-file-name nospecial-foo) nospecial-foo)))) + (should (equal (substitute-in-file-name nospecial-foo) nospecial-foo))))) (ert-deftest files-tests-file-name-non-special-temporary-file-directory () (files-tests--with-temp-non-special (tmpdir nospecial-dir t) (let ((default-directory nospecial-dir)) - (equal (temporary-file-directory) temporary-file-directory))) + (should (equal (temporary-file-directory) temporary-file-directory)))) (files-tests--with-temp-non-special-and-file-name-handler (tmpdir nospecial-dir t) (let ((default-directory nospecial-dir)) - (equal (temporary-file-directory) temporary-file-directory)))) + (should (equal (temporary-file-directory) temporary-file-directory))))) (ert-deftest files-tests-file-name-non-special-unhandled-file-name-directory () (files-tests--with-temp-non-special (tmpdir nospecial-dir t) - (equal (unhandled-file-name-directory nospecial-dir) - (file-name-as-directory tmpdir))) + (should (equal (unhandled-file-name-directory nospecial-dir) + (file-name-as-directory tmpdir)))) (files-tests--with-temp-non-special-and-file-name-handler (tmpdir nospecial-dir t) - (equal (unhandled-file-name-directory nospecial-dir) - (file-name-as-directory tmpdir)))) + (should-not (equal (unhandled-file-name-directory nospecial-dir) + (file-name-as-directory tmpdir))))) (ert-deftest files-tests-file-name-non-special-vc-registered () (files-tests--with-temp-non-special (tmpfile nospecial) @@ -1635,6 +1656,31 @@ The door of all subtleties! (should (equal (file-name-base "foo") "foo")) (should (equal (file-name-base "foo/bar") "bar"))) +(defun files-tests--check-shebang (shebang expected-mode) + "Assert that mode for SHEBANG derives from EXPECTED-MODE." + (let ((actual-mode + (ert-with-temp-file script-file + :text shebang + (find-file script-file) + (if (derived-mode-p expected-mode) + expected-mode + major-mode)))) + ;; Tuck all the information we need in the `should' form: input + ;; shebang, expected mode vs actual. + (should + (equal (list shebang actual-mode) + (list shebang expected-mode))))) + +(ert-deftest files-tests-auto-mode-interpreter () + "Test that `set-auto-mode' deduces correct modes from shebangs." + (files-tests--check-shebang "#!/bin/bash" 'sh-mode) + (files-tests--check-shebang "#!/usr/bin/env bash" 'sh-mode) + (files-tests--check-shebang "#!/usr/bin/env python" 'python-base-mode) + (files-tests--check-shebang "#!/usr/bin/env python3" 'python-base-mode) + (files-tests--check-shebang "#!/usr/bin/env -S awk -v FS=\"\\t\" -v OFS=\"\\t\" -f" 'awk-mode) + (files-tests--check-shebang "#!/usr/bin/env -S make -f" 'makefile-mode) + (files-tests--check-shebang "#!/usr/bin/make -f" 'makefile-mode)) + (ert-deftest files-test-dir-locals-auto-mode-alist () "Test an `auto-mode-alist' entry in `.dir-locals.el'" (find-file (ert-resource-file "whatever.quux")) @@ -1696,6 +1742,157 @@ let-bound to PRED and passing nil as second arg of (set-buffer-modified-p nil) (kill-buffer buf))))))) +(defmacro files-tests--with-yes-or-no-p (reply &rest body) + "Execute BODY, providing replies to `yes-or-no-p' queries. +REPLY should be a cons (PROMPT . VALUE), and during execution of +BODY this macro provides VALUE as return value to all +`yes-or-no-p' calls prompting for PROMPT and nil to all other +`yes-or-no-p' calls. After execution of BODY, this macro ensures +that exactly one `yes-or-no-p' call prompting for PROMPT has been +executed during execution of BODY." + (declare (indent 1) (debug (sexp body))) + `(cl-letf* + ((reply ,reply) + (prompts nil) + ((symbol-function 'yes-or-no-p) + (lambda (prompt) + (let ((reply (cdr (assoc prompt (list reply))))) + (push (cons prompt reply) prompts) + reply)))) + ,@body + (should (equal prompts (list reply))))) + +(ert-deftest files-tests-save-buffer-read-only-file () + "Test writing to write-protected files with `save-buffer'. +Ensure that the issues from bug#66546 are fixed." + (ert-with-temp-directory dir + (cl-flet (;; Define convenience functions. + (file-contents (file) + (if (file-exists-p file) + (condition-case err + (with-temp-buffer + (insert-file-contents-literally file) + (buffer-string)) + (error err)) + 'missing)) + (signal-write-failed (&rest _) + (signal 'file-error "Write failed"))) + + (let* (;; Sanitize environment. + ;; The tests below test text for equality, so we need to + ;; disable any code- and EOL-conversions to avoid false + ;; positives and false negatives. + (coding-system-for-read 'no-conversion) + (coding-system-for-write 'no-conversion) + (auto-save-default nil) + (backup-enable-predicate nil) + (before-save-hook nil) + (write-contents-functions nil) + (write-file-functions nil) + (after-save-hook nil) + + ;; Set the name of the game. + (base "read-only-test") + (file (expand-file-name base dir)) + (backup (make-backup-file-name file)) + + (override-read-only-prompt + (format "File %s is write-protected; try to save anyway? " + base))) + + ;; Ensure that set-file-modes renders our test file read-only, + ;; otherwise skip this test. Use `file-writable-p' to test + ;; for read-only-ness, because that's what function + ;; `save-buffer' uses as well. + (with-temp-file file (insert "foo\n")) + (skip-unless (file-writable-p file)) + (set-file-modes file (logand (file-modes file) + (lognot #o0222))) + (skip-unless (not (file-writable-p file))) + + (with-current-buffer (find-file-noselect file) + ;; Prepare for tests backing up the file. + (setq buffer-read-only nil) + (goto-char (point-min)) + (insert "bar\n") + + ;; Save to read-only file with backup, declining prompt. + (files-tests--with-yes-or-no-p + (cons override-read-only-prompt nil) + (should-error + (save-buffer) + ;; "Attempt to save to a file that you aren't allowed to write" + :type 'error)) + (should-not buffer-backed-up) + (should (buffer-modified-p)) + (should-not (file-writable-p file)) + (should (equal (file-contents file) "foo\n")) + (should (equal (file-contents backup) 'missing)) + + ;; Save to read-only file with backup, accepting prompt, + ;; experiencing a write error. + (files-tests--with-yes-or-no-p + (cons override-read-only-prompt t) + (should-error + (cl-letf (((symbol-function 'write-region) + #'signal-write-failed)) + (save-buffer)) + ;; "Write failed" + :type 'file-error)) + (should-not buffer-backed-up) + (should (buffer-modified-p)) + (should-not (file-writable-p file)) + (should (equal (file-contents file) "foo\n")) + (should (equal (file-contents backup) 'missing)) + + ;; Save to read-only file with backup, accepting prompt. + (files-tests--with-yes-or-no-p + (cons override-read-only-prompt t) + (save-buffer)) + (should buffer-backed-up) + (should-not (buffer-modified-p)) + (should-not (file-writable-p file)) + (should-not (file-writable-p backup)) + (should (equal (file-contents file) "bar\nfoo\n")) + (should (equal (file-contents backup) "foo\n")) + + ;; Prepare for tests not backing up the file. + (setq buffer-backed-up nil) + (delete-file backup) + (goto-char (point-min)) + (insert "baz\n") + + ;; Save to read-only file without backup, accepting prompt, + ;; experiencing a write error. This tests that issue B of + ;; bug#66546 is fixed. The results of the "with backup" and + ;; "without backup" subtests are identical when a write + ;; error occurs, but the code paths to reach these results + ;; are not. In other words, this subtest is not redundant. + (files-tests--with-yes-or-no-p + (cons override-read-only-prompt t) + (should-error + (cl-letf (((symbol-function 'write-region) + #'signal-write-failed)) + (save-buffer 0)) + ;; "Write failed" + :type 'file-error)) + (should-not buffer-backed-up) + (should (buffer-modified-p)) + (should-not (file-writable-p file)) + (should (equal (file-contents file) "bar\nfoo\n")) + (should (equal (file-contents backup) 'missing)) + + ;; Save to read-only file without backup, accepting prompt. + ;; This tests that issue A of bug#66546 is fixed. + (files-tests--with-yes-or-no-p + (cons override-read-only-prompt t) + (save-buffer 0)) + (should-not buffer-backed-up) + (should-not (buffer-modified-p)) + (should-not (file-writable-p file)) + (should (equal (file-contents file) "baz\nbar\nfoo\n")) + (should (equal (file-contents backup) 'missing))))))) + (ert-deftest files-tests-save-some-buffers () "Test `save-some-buffers'. Test the 3 cases for the second argument PRED, i.e., nil, t, or @@ -1904,5 +2101,9 @@ Prompt users for any modified buffer with `buffer-offer-save' non-nil." (should (documentation 'bar)) (should (documentation 'zot))))) +(ert-deftest files-tests--expand-wildcards () + (should (file-expand-wildcards + (concat (directory-file-name default-directory) "*/")))) + (provide 'files-tests) ;;; files-tests.el ends here |