diff options
| author | Bozhidar Batsov <bozhidar@toptal.com> | 2026-04-25 18:56:12 +0100 |
|---|---|---|
| committer | Bozhidar Batsov <bozhidar@toptal.com> | 2026-04-25 18:56:12 +0100 |
| commit | 925688ed5c0c7b7a9e97a47eaf2e2c63771aea35 (patch) | |
| tree | 00fb3f8e827edbe59d977773074083b79595886c | |
| parent | 930564202e350d5d6c73d6fc765b1cc29cb48f38 (diff) | |
Add tests for the dirconfig cache
The mtime-keyed cache around projectile-parse-dirconfig-file had no
direct coverage. Cover the four invariants that matter: a cache hit
on repeat calls, a re-parse when mtime advances, no caching of a nil
result for a missing file, and entry removal via
projectile-invalidate-cache (the path that previously crashed in #1854).
| -rw-r--r-- | test/projectile-test.el | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/test/projectile-test.el b/test/projectile-test.el index 4a20e92..f874a83 100644 --- a/test/projectile-test.el +++ b/test/projectile-test.el @@ -574,6 +574,65 @@ Just delegates OPERATION and ARGS for all operations except for`shell-command`'. (expect (projectile-parse-dirconfig-file) :to-equal '(nil ("keep-this") nil))))) +(describe "dirconfig cache" + (before-each + (clrhash projectile--dirconfig-cache)) + (it "memoizes the parsed result while the file is unchanged" + (projectile-test-with-sandbox + (projectile-test-with-files + ("project/.projectile") + (let ((root (file-truename (expand-file-name "project/")))) + (with-temp-file (expand-file-name ".projectile" root) + (insert "-foo\n")) + (spy-on 'projectile-project-root :and-return-value root) + (spy-on 'projectile--parse-dirconfig-file-uncached + :and-call-through) + (projectile-parse-dirconfig-file) + (projectile-parse-dirconfig-file) + (projectile-parse-dirconfig-file) + (expect 'projectile--parse-dirconfig-file-uncached + :to-have-been-called-times 1))))) + (it "re-parses when the dirconfig file's mtime changes" + (projectile-test-with-sandbox + (projectile-test-with-files + ("project/.projectile") + (let* ((root (file-truename (expand-file-name "project/"))) + (dirconfig (expand-file-name ".projectile" root))) + (with-temp-file dirconfig (insert "-foo\n")) + (spy-on 'projectile-project-root :and-return-value root) + (expect (cadr (projectile-parse-dirconfig-file)) + :to-equal '("foo")) + ;; Force a distinct mtime — file-attribute-modification-time has + ;; second-level resolution on some filesystems. + (set-file-times dirconfig (time-add (current-time) 5)) + (with-temp-file dirconfig (insert "-bar\n")) + (set-file-times dirconfig (time-add (current-time) 5)) + (expect (cadr (projectile-parse-dirconfig-file)) + :to-equal '("bar")))))) + (it "returns nil and does not cache when the dirconfig file is absent" + (projectile-test-with-sandbox + (projectile-test-with-files + ("project/") + (let ((root (file-truename (expand-file-name "project/")))) + (spy-on 'projectile-project-root :and-return-value root) + (expect (projectile-parse-dirconfig-file) :to-be nil) + (expect (gethash root projectile--dirconfig-cache) :to-be nil))))) + (it "is cleared for the project by projectile-invalidate-cache" + (projectile-test-with-sandbox + (projectile-test-with-files + ("project/.projectile") + (let ((root (file-truename (expand-file-name "project/")))) + (with-temp-file (expand-file-name ".projectile" root) + (insert "-foo\n")) + (spy-on 'projectile-project-root :and-return-value root) + ;; Avoid touching the on-disk cache file or recentf during the test. + (spy-on 'projectile-persistent-cache-p :and-return-value nil) + (spy-on 'recentf-cleanup) + (projectile-parse-dirconfig-file) + (expect (gethash root projectile--dirconfig-cache) :not :to-be nil) + (projectile-invalidate-cache nil) + (expect (gethash root projectile--dirconfig-cache) :to-be nil)))))) + (describe "projectile-get-project-directories" (it "gets the list of project directories" (spy-on 'projectile-project-root :and-return-value "/my/root/") |
