aboutsummaryrefslogtreecommitdiff
path: root/tests/test-chime-tooltip-bugs.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-chime-tooltip-bugs.el')
-rw-r--r--tests/test-chime-tooltip-bugs.el392
1 files changed, 392 insertions, 0 deletions
diff --git a/tests/test-chime-tooltip-bugs.el b/tests/test-chime-tooltip-bugs.el
new file mode 100644
index 0000000..dce2fa5
--- /dev/null
+++ b/tests/test-chime-tooltip-bugs.el
@@ -0,0 +1,392 @@
+;;; test-chime-tooltip-bugs.el --- Tests for tooltip bugs -*- lexical-binding: t; -*-
+
+;; Tests for reported issues:
+;; 1. Duplicate "in in" in countdown text
+;; 2. Duplicate events in tooltip
+;; 3. Missing future events
+
+;;; Code:
+
+(when noninteractive
+ (package-initialize))
+
+(require 'ert)
+(require 'dash)
+(require 'alert)
+(require 'async)
+(require 'org-agenda)
+(load (expand-file-name "../chime.el") nil t)
+(require 'testutil-general (expand-file-name "testutil-general.el"))
+(require 'testutil-time (expand-file-name "testutil-time.el"))
+
+;;; Setup and Teardown
+
+(defun test-tooltip-bugs-setup ()
+ "Setup function run before each test."
+ (chime-create-test-base-dir)
+ (setq test-tooltip-bugs--orig-lookahead chime-modeline-lookahead-minutes)
+ (setq test-tooltip-bugs--orig-tooltip-lookahead chime-tooltip-lookahead-hours)
+ (setq chime-modeline-lookahead-minutes 1440)
+ (setq chime-tooltip-lookahead-hours 8760)) ; 1 year
+
+(defun test-tooltip-bugs-teardown ()
+ "Teardown function run after each test."
+ (setq chime-modeline-lookahead-minutes test-tooltip-bugs--orig-lookahead)
+ (setq chime-tooltip-lookahead-hours test-tooltip-bugs--orig-tooltip-lookahead)
+ (chime-delete-test-base-dir))
+
+(defvar test-tooltip-bugs--orig-lookahead nil)
+(defvar test-tooltip-bugs--orig-tooltip-lookahead nil)
+
+;;; Helper functions
+
+(defun test-tooltip-bugs--create-gcal-event (title time-str)
+ "Create test org content for a gcal event."
+ (concat
+ (format "* %s\n" title)
+ ":PROPERTIES:\n"
+ ":entry-id: test@google.com\n"
+ ":END:\n"
+ ":org-gcal:\n"
+ (format "%s\n" time-str)
+ ":END:\n"))
+
+(defun test-tooltip-bugs--gather-events (content)
+ "Process CONTENT and return events list."
+ (let* ((test-file (chime-create-temp-test-file-with-content content))
+ (test-buffer (find-file-noselect test-file))
+ (events nil))
+ (with-current-buffer test-buffer
+ (org-mode)
+ (goto-char (point-min))
+ (while (re-search-forward "^\\*+ " nil t)
+ (beginning-of-line)
+ (let* ((marker (point-marker))
+ (info (chime--gather-info marker)))
+ (push info events))
+ (forward-line 1)))
+ (kill-buffer test-buffer)
+ (nreverse events)))
+
+(defun test-tooltip-bugs--count-in-string (regexp string)
+ "Count occurrences of REGEXP in STRING."
+ (let ((count 0)
+ (start 0))
+ (while (string-match regexp string start)
+ (setq count (1+ count))
+ (setq start (match-end 0)))
+ count))
+
+;;; Test 1: No duplicate "in" in countdown text
+
+(ert-deftest test-tooltip-no-duplicate-in ()
+ "Test that tooltip doesn't have duplicate 'in in' in countdown.
+
+Issue: Tooltip showed '(in in 1h 4m)' instead of '(in 1h 4m)'."
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (test-time-now))
+ (event-time (time-add now (seconds-to-time (* 90 60)))) ; 90 min from now
+ (time-str (format-time-string "<%Y-%m-%d %a %H:%M>" event-time))
+ (content (test-tooltip-bugs--create-gcal-event "Test Event" time-str))
+ (events (test-tooltip-bugs--gather-events content)))
+
+ (with-test-time now
+ (chime--update-modeline events))
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; Should NOT have "in in"
+ (should-not (string-match-p "in in" tooltip))
+
+ ;; Should have single "in" (from format string)
+ (should (string-match-p "(in " tooltip))))
+ (test-tooltip-bugs-teardown)))
+
+;;; Test 2: No duplicate events in tooltip
+
+(ert-deftest test-tooltip-no-duplicate-events ()
+ "Test that same event doesn't appear multiple times in tooltip.
+
+Issue: Events appeared multiple times in tooltip."
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (test-time-now))
+ (event1-time (time-add now (seconds-to-time (* 60 60)))) ; 1 hour
+ (event1-str (format-time-string "<%Y-%m-%d %a %H:%M>" event1-time))
+ (event2-time (time-add now (seconds-to-time (* 120 60)))) ; 2 hours
+ (event2-str (format-time-string "<%Y-%m-%d %a %H:%M>" event2-time))
+ (content (concat
+ (test-tooltip-bugs--create-gcal-event "Task 1" event1-str)
+ (test-tooltip-bugs--create-gcal-event "Task 2" event2-str)))
+ (events (test-tooltip-bugs--gather-events content)))
+
+ (with-test-time now
+ (chime--update-modeline events))
+
+ ;; Should have exactly 2 events
+ (should (= 2 (length chime--upcoming-events)))
+
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; Each event should appear exactly once
+ (should (= 1 (test-tooltip-bugs--count-in-string "Task 1" tooltip)))
+ (should (= 1 (test-tooltip-bugs--count-in-string "Task 2" tooltip)))))
+ (test-tooltip-bugs-teardown)))
+
+;;; Test 3: All future events included (not just first few in file)
+
+(ert-deftest test-tooltip-includes-all-future-events ()
+ "Test that tooltip includes all future events, not just first N in file.
+
+Issue: Events later in file were being ignored.
+This tests that chime doesn't assume events are in chronological order in file."
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (test-time-now))
+ ;; Create events in NON-chronological order in file
+ ;; Far event first, then near events
+ (event-far-time (time-add now (seconds-to-time (* 48 3600)))) ; 2 days
+ (event-far-str (format-time-string "<%Y-%m-%d %a %H:%M>" event-far-time))
+ (event1-time (time-add now (seconds-to-time (* 60 60)))) ; 1 hour
+ (event1-str (format-time-string "<%Y-%m-%d %a %H:%M>" event1-time))
+ (event2-time (time-add now (seconds-to-time (* 90 60)))) ; 1.5 hours
+ (event2-str (format-time-string "<%Y-%m-%d %a %H:%M>" event2-time))
+ (content (concat
+ ;; Far event appears FIRST in file
+ (test-tooltip-bugs--create-gcal-event "Task Far" event-far-str)
+ ;; Near events appear AFTER in file
+ (test-tooltip-bugs--create-gcal-event "Task 1" event1-str)
+ (test-tooltip-bugs--create-gcal-event "Task 2" event2-str)))
+ (events (test-tooltip-bugs--gather-events content)))
+
+ ;; Mock time to prevent timing-related flakiness
+ (with-test-time now
+ (chime--update-modeline events))
+
+ ;; Should have all 3 events
+ (should (= 3 (length chime--upcoming-events)))
+
+ ;; Events should be in chronological order (not file order)
+ (let* ((item1 (nth 0 chime--upcoming-events))
+ (item2 (nth 1 chime--upcoming-events))
+ (item3 (nth 2 chime--upcoming-events))
+ (title1 (cdr (assoc 'title (car item1))))
+ (title2 (cdr (assoc 'title (car item2))))
+ (title3 (cdr (assoc 'title (car item3)))))
+ ;; Should be sorted chronologically
+ (should (string= title1 "Task 1"))
+ (should (string= title2 "Task 2"))
+ (should (string= title3 "Task Far")))
+
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; All events should appear in tooltip
+ (should (string-match-p "Task 1" tooltip))
+ (should (string-match-p "Task 2" tooltip))
+ (should (string-match-p "Task Far" tooltip))
+
+ ;; Chronological order: Task 1 before Task 2 before Task Far
+ (let ((pos1 (string-match "Task 1" tooltip))
+ (pos2 (string-match "Task 2" tooltip))
+ (pos-far (string-match "Task Far" tooltip)))
+ (should (< pos1 pos2))
+ (should (< pos2 pos-far)))))
+ (test-tooltip-bugs-teardown)))
+
+;;; Test 4: Exact replication of reported duplicate event issue
+
+(ert-deftest test-tooltip-exact-duplicate-bug ()
+ "Replicate exact bug: Task 2 appearing twice, Task 3 appearing twice.
+
+From user report:
+Task 1 at 9:00 PM (in 1h 4m)
+Task 2 at 10:00 PM (in 2h 4m) <-- appears
+Task 3 at 10:00 PM (in 2h 4m) <-- appears
+Task 2 at 10:00 PM (in 2h 4m) <-- DUPLICATE
+Task 4 at 01:00 PM (in 17h 4m)"
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (current-time))
+ ;; Create exactly the scenario from the report
+ (task1-time (time-add now (seconds-to-time (* 64 60)))) ; ~1h 4m
+ (task1-str (format-time-string "<%Y-%m-%d %a %H:%M>" task1-time))
+ (task2-time (time-add now (seconds-to-time (* 124 60)))) ; ~2h 4m
+ (task2-str (format-time-string "<%Y-%m-%d %a %H:%M>" task2-time))
+ (task3-time (time-add now (seconds-to-time (* 124 60)))) ; same time as task2
+ (task3-str (format-time-string "<%Y-%m-%d %a %H:%M>" task3-time))
+ (task4-time (time-add now (seconds-to-time (* 1024 60)))) ; ~17h 4m
+ (task4-str (format-time-string "<%Y-%m-%d %a %H:%M>" task4-time))
+ (content (concat
+ (test-tooltip-bugs--create-gcal-event "Task 1" task1-str)
+ (test-tooltip-bugs--create-gcal-event "Task 2" task2-str)
+ (test-tooltip-bugs--create-gcal-event "Task 3" task3-str)
+ (test-tooltip-bugs--create-gcal-event "Task 4" task4-str)))
+ (events (test-tooltip-bugs--gather-events content)))
+
+ (chime--update-modeline events)
+
+ ;; Should have exactly 4 events
+ (should (= 4 (length chime--upcoming-events)))
+
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; Each event should appear exactly once (no duplicates)
+ (should (= 1 (test-tooltip-bugs--count-in-string "Task 1" tooltip)))
+ (should (= 1 (test-tooltip-bugs--count-in-string "Task 2" tooltip)))
+ (should (= 1 (test-tooltip-bugs--count-in-string "Task 3" tooltip)))
+ (should (= 1 (test-tooltip-bugs--count-in-string "Task 4" tooltip)))
+
+ ;; Verify chronological order
+ (let ((pos1 (string-match "Task 1" tooltip))
+ (pos2 (string-match "Task 2" tooltip))
+ (pos3 (string-match "Task 3" tooltip))
+ (pos4 (string-match "Task 4" tooltip)))
+ (should (< pos1 pos2))
+ (should (< pos2 pos4)))))
+ (test-tooltip-bugs-teardown)))
+
+;;; Test 5: Missing events that appear later in file
+
+(ert-deftest test-tooltip-missing-later-events ()
+ "Replicate exact bug: Tasks 5, 6, 7 missing even though they're in future.
+
+From user report: 'Earlier in the same org-gcal file, I have Tasks 5, 6, 7
+and many more in the future.'
+
+This tests the concern: 'I worry chime is somehow assuming events and dates
+are always listed in chronological order.'"
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (current-time))
+ ;; Create scenario where early events appear AFTER later events in file
+ ;; This mimics how org-gcal might organize events
+ (task5-time (time-add now (seconds-to-time (* 30 3600)))) ; 30 hours (tomorrow)
+ (task5-str (format-time-string "<%Y-%m-%d %a %H:%M>" task5-time))
+ (task6-time (time-add now (seconds-to-time (* 48 3600)))) ; 48 hours (2 days)
+ (task6-str (format-time-string "<%Y-%m-%d %a %H:%M>" task6-time))
+ (task7-time (time-add now (seconds-to-time (* 72 3600)))) ; 72 hours (3 days)
+ (task7-str (format-time-string "<%Y-%m-%d %a %H:%M>" task7-time))
+ (task1-time (time-add now (seconds-to-time (* 2 3600)))) ; 2 hours (soon!)
+ (task1-str (format-time-string "<%Y-%m-%d %a %H:%M>" task1-time))
+ ;; Put far events FIRST in file, near event LAST
+ (content (concat
+ (test-tooltip-bugs--create-gcal-event "Task 5" task5-str)
+ (test-tooltip-bugs--create-gcal-event "Task 6" task6-str)
+ (test-tooltip-bugs--create-gcal-event "Task 7" task7-str)
+ (test-tooltip-bugs--create-gcal-event "Task 1" task1-str)))
+ (events (test-tooltip-bugs--gather-events content)))
+
+ (chime--update-modeline events)
+
+ ;; Should have all 4 events
+ (should (= 4 (length chime--upcoming-events)))
+
+ ;; Events should be sorted chronologically (not file order)
+ (let* ((item1 (nth 0 chime--upcoming-events))
+ (item2 (nth 1 chime--upcoming-events))
+ (item3 (nth 2 chime--upcoming-events))
+ (item4 (nth 3 chime--upcoming-events))
+ (title1 (cdr (assoc 'title (car item1))))
+ (title2 (cdr (assoc 'title (car item2))))
+ (title3 (cdr (assoc 'title (car item3))))
+ (title4 (cdr (assoc 'title (car item4)))))
+ (should (string= title1 "Task 1")) ; soonest
+ (should (string= title2 "Task 5"))
+ (should (string= title3 "Task 6"))
+ (should (string= title4 "Task 7"))) ; furthest
+
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; ALL events should be present
+ (should (string-match-p "Task 1" tooltip))
+ (should (string-match-p "Task 5" tooltip))
+ (should (string-match-p "Task 6" tooltip))
+ (should (string-match-p "Task 7" tooltip))
+
+ ;; Verify chronological order in tooltip
+ (let ((pos1 (string-match "Task 1" tooltip))
+ (pos5 (string-match "Task 5" tooltip))
+ (pos6 (string-match "Task 6" tooltip))
+ (pos7 (string-match "Task 7" tooltip)))
+ (should (< pos1 pos5))
+ (should (< pos5 pos6))
+ (should (< pos6 pos7)))))
+ (test-tooltip-bugs-teardown)))
+
+;;; Test 6: Only 5 events shown when many more exist
+
+(ert-deftest test-tooltip-only-first-5-shown ()
+ "Replicate bug: Only 5 events shown in tooltip despite having many more.
+
+From user report: Tooltip showed 5 events, then '...and that's all' even
+though there were many more future events in the file.
+
+This might be due to default max-events=5."
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (test-time-now))
+ (content "")
+ (events nil))
+
+ ;; Create 10 events
+ (dotimes (i 10)
+ (let* ((hours-offset (+ 1 i)) ; 1, 2, 3... 10 hours
+ (event-time (time-add now (seconds-to-time (* hours-offset 3600))))
+ (time-str (format-time-string "<%Y-%m-%d %a %H:%M>" event-time))
+ (title (format "Task %d" (1+ i))))
+ (setq content (concat content
+ (test-tooltip-bugs--create-gcal-event title time-str)))))
+
+ (setq events (test-tooltip-bugs--gather-events content))
+
+ ;; Set to default: max-events=5
+ (let ((chime-modeline-tooltip-max-events 5))
+ (with-test-time now
+ (chime--update-modeline events))
+
+ ;; All 10 events should be in upcoming-events
+ (should (= 10 (length chime--upcoming-events)))
+
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; Tooltip should show first 5 events
+ (should (string-match-p "Task 1" tooltip))
+ (should (string-match-p "Task 2" tooltip))
+ (should (string-match-p "Task 3" tooltip))
+ (should (string-match-p "Task 4" tooltip))
+ (should (string-match-p "Task 5" tooltip))
+
+ ;; Should NOT show tasks 6-10
+ (should-not (string-match-p "Task 6" tooltip))
+ (should-not (string-match-p "Task 10" tooltip))
+
+ ;; Should show "... and 5 more events"
+ (should (string-match-p "\\.\\.\\..*and 5 more events" tooltip)))))
+ (test-tooltip-bugs-teardown)))
+
+;;; Test 7: Events at exactly same time
+
+(ert-deftest test-tooltip-events-same-time ()
+ "Test events scheduled at exactly the same time.
+
+From user report: Task 2 and Task 3 both at 10:00 PM.
+Should both appear, should not duplicate."
+ (test-tooltip-bugs-setup)
+ (unwind-protect
+ (let* ((now (current-time))
+ (same-time (time-add now (seconds-to-time (* 120 60)))) ; 2 hours
+ (time-str (format-time-string "<%Y-%m-%d %a %H:%M>" same-time))
+ (content (concat
+ (test-tooltip-bugs--create-gcal-event "Meeting A" time-str)
+ (test-tooltip-bugs--create-gcal-event "Meeting B" time-str)
+ (test-tooltip-bugs--create-gcal-event "Meeting C" time-str)))
+ (events (test-tooltip-bugs--gather-events content)))
+
+ (chime--update-modeline events)
+
+ ;; Should have all 3 events
+ (should (= 3 (length chime--upcoming-events)))
+
+ (let ((tooltip (chime--make-tooltip chime--upcoming-events)))
+ ;; All 3 events should appear exactly once
+ (should (= 1 (test-tooltip-bugs--count-in-string "Meeting A" tooltip)))
+ (should (= 1 (test-tooltip-bugs--count-in-string "Meeting B" tooltip)))
+ (should (= 1 (test-tooltip-bugs--count-in-string "Meeting C" tooltip)))))
+ (test-tooltip-bugs-teardown)))
+
+(provide 'test-chime-tooltip-bugs)
+;;; test-chime-tooltip-bugs.el ends here