;;; filelock-tests.el --- test file locking -*- lexical-binding: t; -*- ;; Copyright (C) 2021 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 this program. If not, see . ;;; Commentary: ;; This file tests code in src/filelock.c and, to some extent, the ;; related code in src/fileio.c. ;;; Code: (require 'ert) (defun filelock-tests--call-with-fixture (body) (let ((test-dir (make-temp-file "filelock-tests-" t))) (unwind-protect (let ((file-name (concat (file-name-as-directory test-dir)))) (with-temp-buffer (setq-local buffer-file-name file-name) (setq-local buffer-file-truename file-name) (unwind-protect (save-current-buffer (let ((create-lockfiles t)) (funcall body))) (set-buffer-modified-p nil)))) (delete-directory test-dir t nil)))) (defmacro filelock-tests--with-fixture (&rest body) "Create a test fixture and evaluate BODY there like `progn'. Create a temporary directory, then create a temporary buffer and set it the variable `buffer-file-name' and `buffer-file-truename' to it, let bind `create-lockfiles' to 't' and evaluate BODY." (declare (indent 0)) `(filelock-tests--call-with-fixture (lambda () ,@body))) (defun filelock-tests--call-with-directory-modes (modes body) (let* ((dir (file-name-directory (buffer-file-name))) (original-modes (file-modes dir))) (set-file-modes dir modes) (unwind-protect (funcall body) (set-file-modes dir original-modes)))) (defmacro filelock-tests--with-directory-modes (modes &rest body) "Evaluate BODY forms with directory MODES set. The directory is taken from the buffer local variable `buffer-file-name'. Afterwards, restore the modes to what they were." (declare (indent 1)) `(filelock-tests--call-with-directory-modes ,modes (lambda () ,@body))) (ert-deftest filelock-tests-lock-buffer-permission-denied () "Check that locking a buffer in a directory with no write permissions does not work." (filelock-tests--with-fixture (should (not (file-locked-p (buffer-file-name)))) (filelock-tests--with-directory-modes #o500 ;; FIXME: (lock-buffer) should raise some sort of ;; error/warning here that we should verify in test. ;; Currently lock_file() ignores errors from lock_if_free(). ;; See the related FIXME in filelock.c. (lock-buffer) (should (not (file-locked-p (buffer-file-name))))))) (ert-deftest filelock-tests-file-locked-p-permission-denied () "Check that `file-locked-p' fails if the directory is inaccesible." (filelock-tests--with-fixture (filelock-tests--with-directory-modes #o000 (set-buffer-modified-p t) ;; FIXME: Bug#46397: `file-locked-p' currently signals errors, ;; but this prevents the user from killing the buffer. It also ;; prevents Emacs shutdown. (should (equal (butlast (should-error (file-locked-p (buffer-file-name))) 2) '(file-error "Testing file lock")))))) (ert-deftest filelock-tests-unlock-permission-denied () "Check that `unlock-buffer' fails in directories that cannot be modified." (filelock-tests--with-fixture (set-buffer-modified-p t) (lock-buffer) (should (file-locked-p (buffer-file-name))) (filelock-tests--with-directory-modes #o500 ;; FIXME: Bug#46397: `unlock-buffer' currently signals errors, ;; but this prevents the user from killing the buffer. It also ;; prevents Emacs shutdown. (should (equal (butlast (should-error (unlock-buffer)) 2) '(file-error "Unlocking file")))))) (provide 'filelock-tests) ;;; filelock-tests.el ends here