I've attached a draft patch. This is the first time I'm building a unit
test file from scratch so I tried to follow the examples in other files. If
we add more unit tests it might be worth creating some macros and helper
functions, but I didn't want to overdo it on the first round.

Cheers,

Derek

On Sun, Sep 20, 2026 at 12:19 PM Ihor Radchenko <[email protected]> wrote:

> Derek Chen-Becker <[email protected]> writes:
>
> > It definitely looks like a bug.
>
> Yes, looks like a bug.
>
> > Ihor, I think you touched this last. I don't see any unit tests for
> > org-persist, but I'm not sure if maybe I'm missing something. I'm happy
> to
> > add a new unit test file if needed.
>
> Unit tests would be welcome.
>
> --
> Ihor Radchenko // yantar92,
> Org mode maintainer,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>
>


-- 
+---------------------------------------------------------------+
| Derek Chen-Becker                                             |
| GPG Key available at https://keybase.io/dchenbecker and       |
| https://pgp.mit.edu/pks/lookup?search=derek%40chen-becker.org |
| Fngrprnt: EB8A 6480 F0A3 C8EB C1E7  7F42 AFC5 AFEE 96E4 6ACC  |
+---------------------------------------------------------------+
From 8d2064c96722fe22082ed3ffbf2172436b114fa2 Mon Sep 17 00:00:00 2001
From: Derek Chen-Becker <[email protected]>
Date: Sun, 20 Sep 2026 20:44:27 -0600
Subject: [PATCH] org-persist: Fix inverted GC age calculation

Compute the age of each GC record by subtracting its time from the current
time (inverted in the previous version).

* lisp/org-persist.el (org-persist--refresh-gc-lock): Change age
computation to properly compare against the current time.  Also simplify
the age computation by using time-subtract instead of float arithmetic.

* testing/lisp/test-org-persist.el: Add a new unit test file for
org-persist, along with a unit test specifically for
`org-persist--refresh-gc-lock'.
---
 lisp/org-persist.el              |  6 ++--
 testing/lisp/test-org-persist.el | 53 ++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 3 deletions(-)
 create mode 100644 testing/lisp/test-org-persist.el

diff --git a/lisp/org-persist.el b/lisp/org-persist.el
index 9f3edab82..ee3799ed1 100644
--- a/lisp/org-persist.el
+++ b/lisp/org-persist.el
@@ -1272,9 +1272,9 @@ Remove expired sessions timestamps."
       (setf (alist-get before-init-time alist nil nil #'equal)
             (current-time))
       (dolist (record alist)
-        (when (< (- (float-time (cdr record)) (float-time (current-time)))
-                 org-persist-gc-lock-expiry)
-          (push record new-alist)))
+        (let ((age (float-time (time-subtract nil (cdr record)))))
+          (when (< age org-persist-gc-lock-expiry)
+            (push record new-alist))))
       (ignore-errors (org-persist--write-elisp-file file new-alist)))))
 
 (defun org-persist--gc-orphan-p ()
diff --git a/testing/lisp/test-org-persist.el b/testing/lisp/test-org-persist.el
new file mode 100644
index 000000000..c792c4726
--- /dev/null
+++ b/testing/lisp/test-org-persist.el
@@ -0,0 +1,53 @@
+;;; test-org-persist.el --- Tests for org-persist.el     -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2026, Derek Chen-Becker
+
+;; Author: Derek Chen-Becker <oss at chen-becker dot org>
+
+;; This file is not part of GNU Emacs.
+
+;; This program 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.
+
+;; This program 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 <https://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+;;
+
+;;; Code:
+
+(require 'org-test "../testing/org-test")
+
+(ert-deftest test-org-persist/refresh-gc-lock ()
+  "Test that the GC lock refresh properly handles valid and expired sessions."
+  (let* ((org-persist-gc-lock-expiry 60) ;; Set expiry to keep test data simple
+         (org-persist--wrote-to-disk t) ;; Make sure we actually trigger GC
+         (test-directory (make-temp-file "org-persist-test" t))
+         (org-persist-directory test-directory)
+         (lockfile (concat test-directory "/" org-persist-gc-lock-file))
+         ;; Started 42 seconds ago, should stay
+         (current-record `(,(time-subtract nil 42) . ,(current-time)))
+         ;; Ended 95 seconds ago, should be expired
+         (expired-record `(,(time-subtract nil 120) . ,(time-subtract nil 95))))
+    (unwind-protect
+        (progn
+          (org-persist--write-elisp-file lockfile (list current-record expired-record))
+          (org-persist--refresh-gc-lock)
+          ;; Now re-read the lock file and ensure that all entries are current now
+          (dolist (record (org-persist--read-elisp-file lockfile))
+                  (should-not
+                   (> (float-time (time-subtract nil (cdr record)))
+                      org-persist-gc-lock-expiry))))
+        (delete-directory test-directory t))))
+
+(provide 'test-org-persist)
+;;; test-org-persist.el ends here
-- 
2.43.0

Reply via email to