diff options
| -rw-r--r-- | modules/modeline-config.el | 8 | ||||
| -rw-r--r-- | tests/test-modeline-config-vc-cache-key.el | 56 |
2 files changed, 62 insertions, 2 deletions
diff --git a/modules/modeline-config.el b/modules/modeline-config.el index 61ab0f9d..5afe226e 100644 --- a/modules/modeline-config.el +++ b/modules/modeline-config.el @@ -129,8 +129,12 @@ Uses built-in cached values for performance.") cj/modeline-vc-cache-set-p nil)) (defun cj/modeline-vc-cache-key (file) - "Return the cache key for FILE." - (list file cj/modeline-vc-show-remote)) + "Return the cache key for FILE. +Includes the resolved `file-truename' so that if FILE is a symlink whose +target moves to a different VC tree, the key changes and the cache is not +served a stale backend. The extra `file-truename' is one stat per refresh, +cheap next to the VC calls the cache avoids." + (list file (file-truename file) cj/modeline-vc-show-remote)) (defun cj/modeline-vc-cache-valid-p (key now) "Return non-nil when cached VC data is valid for KEY at NOW." diff --git a/tests/test-modeline-config-vc-cache-key.el b/tests/test-modeline-config-vc-cache-key.el new file mode 100644 index 00000000..ae869f4b --- /dev/null +++ b/tests/test-modeline-config-vc-cache-key.el @@ -0,0 +1,56 @@ +;;; test-modeline-config-vc-cache-key.el --- Tests for VC modeline cache key -*- lexical-binding: t; -*- + +;;; Commentary: +;; The VC modeline cache keys on the file. A symlink whose target moves to a +;; different VC tree must invalidate the cache, so the key includes the +;; resolved `file-truename', not just the symlink path. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'modeline-config) + +;;; Normal Cases + +(ert-deftest test-modeline-vc-cache-key-includes-truename () + "Normal: the cache key includes the resolved truename of the file." + (let ((f (make-temp-file "cj-mlkey-"))) + (unwind-protect + (should (member (file-truename f) (cj/modeline-vc-cache-key f))) + (delete-file f)))) + +;;; Boundary Cases + +(ert-deftest test-modeline-vc-cache-key-changes-when-symlink-target-moves () + "Boundary: re-pointing a symlink to a new target changes the cache key. +The symlink path is identical both times; only its truename differs, so a +key that ignored the truename would serve a stale VC backend." + (let* ((dir (make-temp-file "cj-mlkey-dir-" t)) + (target-a (expand-file-name "a" dir)) + (target-b (expand-file-name "b" dir)) + (link (expand-file-name "link" dir))) + (unwind-protect + (progn + (write-region "" nil target-a) + (write-region "" nil target-b) + (make-symbolic-link target-a link) + (let ((key-a (cj/modeline-vc-cache-key link))) + (delete-file link) + (make-symbolic-link target-b link) + (let ((key-b (cj/modeline-vc-cache-key link))) + (should-not (equal key-a key-b))))) + (delete-directory dir t)))) + +(ert-deftest test-modeline-vc-cache-key-stable-for-same-file () + "Boundary: the key is stable across calls for an unchanged file." + (let ((f (make-temp-file "cj-mlkey-stable-"))) + (unwind-protect + (should (equal (cj/modeline-vc-cache-key f) + (cj/modeline-vc-cache-key f))) + (delete-file f)))) + +(provide 'test-modeline-config-vc-cache-key) +;;; test-modeline-config-vc-cache-key.el ends here |
