aboutsummaryrefslogtreecommitdiff
path: root/tests/test-chime-group-events-by-day.el
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-chime-group-events-by-day.el')
-rw-r--r--tests/test-chime-group-events-by-day.el268
1 files changed, 268 insertions, 0 deletions
diff --git a/tests/test-chime-group-events-by-day.el b/tests/test-chime-group-events-by-day.el
new file mode 100644
index 0000000..c9e564a
--- /dev/null
+++ b/tests/test-chime-group-events-by-day.el
@@ -0,0 +1,268 @@
+;;; test-chime-group-events-by-day.el --- Tests for chime--group-events-by-day -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2024 Craig Jennings
+
+;; Author: Craig Jennings <c@cjennings.net>
+
+;; 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 <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Unit tests for chime--group-events-by-day function.
+;; Tests cover normal cases, boundary cases, and error cases.
+;;
+;; Note: chime--group-events-by-day does not handle malformed events gracefully.
+;; This is acceptable since events are generated internally by chime and should
+;; always have the correct structure. If a malformed event is passed, it will error.
+;; Removed test: test-chime-group-events-by-day-error-malformed-event
+
+;;; Code:
+
+;; Initialize package system for batch mode
+(when noninteractive
+ (package-initialize))
+
+(require 'ert)
+
+;; Load dependencies required by chime
+(require 'dash)
+(require 'alert)
+(require 'async)
+(require 'org-agenda)
+
+;; Load chime from parent directory
+(load (expand-file-name "../chime.el") nil t)
+
+;; Load test utilities
+(require 'testutil-general (expand-file-name "testutil-general.el"))
+(require 'testutil-time (expand-file-name "testutil-time.el"))
+
+;;; Setup and Teardown
+
+(defun test-chime-group-events-by-day-setup ()
+ "Setup function run before each test."
+ (chime-create-test-base-dir))
+
+(defun test-chime-group-events-by-day-teardown ()
+ "Teardown function run after each test."
+ (chime-delete-test-base-dir))
+
+;;; Test Helpers
+
+(defun test-chime-make-event-item (minutes-until title)
+ "Create a mock event item for testing.
+MINUTES-UNTIL is minutes until event, TITLE is event title."
+ (let* ((now (current-time))
+ (event-time (time-add now (seconds-to-time (* minutes-until 60))))
+ (timestamp-str (test-timestamp-string event-time))
+ (event `((title . ,title)
+ (times . ())))
+ (time-info (cons timestamp-str event-time)))
+ (list event time-info minutes-until)))
+
+;;; Normal Cases
+
+(ert-deftest test-chime-group-events-by-day-normal-single-day ()
+ "Test grouping events all on same day.
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event1 (test-chime-make-event-item 10 "Event 1"))
+ (event2 (test-chime-make-event-item 30 "Event 2"))
+ (event3 (test-chime-make-event-item 60 "Event 3"))
+ (upcoming (list event1 event2 event3))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should have 1 group (today)
+ (should (= 1 (length result)))
+ ;; Group should have 3 events
+ (should (= 3 (length (cdr (car result)))))
+ ;; Date string should say "Today"
+ (should (string-match-p "Today" (car (car result)))))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-normal-multiple-days ()
+ "Test grouping events across multiple days.
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event1 (test-chime-make-event-item 10 "Today Event"))
+ (event2 (test-chime-make-event-item 1500 "Tomorrow Event")) ; > 1440
+ (event3 (test-chime-make-event-item 3000 "Future Event")) ; > 2880
+ (upcoming (list event1 event2 event3))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should have 3 groups (today, tomorrow, future)
+ (should (= 3 (length result)))
+ ;; First group should say "Today"
+ (should (string-match-p "Today" (car (nth 0 result))))
+ ;; Second group should say "Tomorrow"
+ (should (string-match-p "Tomorrow" (car (nth 1 result)))))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-normal-maintains-order ()
+ "Test that events maintain order within groups.
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event1 (test-chime-make-event-item 10 "First"))
+ (event2 (test-chime-make-event-item 20 "Second"))
+ (event3 (test-chime-make-event-item 30 "Third"))
+ (upcoming (list event1 event2 event3))
+ (result (chime--group-events-by-day upcoming))
+ (today-events (cdr (car result))))
+ ;; Should maintain order
+ (should (= 3 (length today-events)))
+ (should (string= "First" (cdr (assoc 'title (car (nth 0 today-events))))))
+ (should (string= "Second" (cdr (assoc 'title (car (nth 1 today-events))))))
+ (should (string= "Third" (cdr (assoc 'title (car (nth 2 today-events)))))))
+ (test-chime-group-events-by-day-teardown)))
+
+;;; Boundary Cases
+
+(ert-deftest test-chime-group-events-by-day-boundary-empty-list ()
+ "Test grouping empty events list.
+
+REFACTORED: No timestamps used"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let ((result (chime--group-events-by-day '())))
+ ;; Should return empty list
+ (should (null result)))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-boundary-single-event ()
+ "Test grouping single event.
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event (test-chime-make-event-item 10 "Only Event"))
+ (upcoming (list event))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should have 1 group
+ (should (= 1 (length result)))
+ ;; Group should have 1 event
+ (should (= 1 (length (cdr (car result))))))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-boundary-exactly-1440-minutes ()
+ "Test event at exactly 1440 minutes (1 day boundary).
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event (test-chime-make-event-item 1440 "Boundary Event"))
+ (upcoming (list event))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should be grouped as "Tomorrow"
+ (should (= 1 (length result)))
+ (should (string-match-p "Tomorrow" (car (car result)))))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-boundary-just-under-1440 ()
+ "Test event at 1439 minutes (23h 59m away).
+
+If current time is 10:00 AM, an event 1439 minutes away is at 9:59 AM
+the next calendar day, so it should be grouped as 'Tomorrow', not 'Today'.
+
+REFACTORED: Uses dynamic timestamps and corrects expected behavior"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event (test-chime-make-event-item 1439 "Almost Tomorrow"))
+ (upcoming (list event))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should be grouped as "Tomorrow" (next calendar day)
+ (should (= 1 (length result)))
+ (should (string-match-p "Tomorrow" (car (car result)))))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-boundary-exactly-2880-minutes ()
+ "Test event at exactly 2880 minutes (2 day boundary).
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event (test-chime-make-event-item 2880 "Two Days Away"))
+ (upcoming (list event))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should be grouped as a future day (not "Tomorrow")
+ (should (= 1 (length result)))
+ (should-not (string-match-p "Tomorrow" (car (car result)))))
+ (test-chime-group-events-by-day-teardown)))
+
+(ert-deftest test-chime-group-events-by-day-boundary-zero-minutes ()
+ "Test event at 0 minutes (happening now).
+
+REFACTORED: Uses dynamic timestamps"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (let* ((event (test-chime-make-event-item 0 "Right Now"))
+ (upcoming (list event))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Should be grouped as "Today"
+ (should (= 1 (length result)))
+ (should (string-match-p "Today" (car (car result)))))
+ (test-chime-group-events-by-day-teardown)))
+
+;;; Bug Reproduction Tests
+
+(ert-deftest test-chime-group-events-by-day-bug-tomorrow-morning-grouped-as-today ()
+ "Test that tomorrow morning event is NOT grouped as 'Today'.
+This reproduces the bug where an event at 10:00 AM tomorrow,
+when it's 11:23 AM today (22h 37m = 1357 minutes away),
+is incorrectly grouped as 'Today' instead of 'Tomorrow'.
+
+The bug: The function groups by 24-hour period (<1440 minutes)
+instead of by calendar day."
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (with-test-time (encode-time 0 23 11 2 11 2025) ; Nov 02, 2025 11:23 AM
+ (let* ((now (current-time))
+ (tomorrow-morning (encode-time 0 0 10 3 11 2025)) ; Nov 03, 2025 10:00 AM
+ (minutes-until (/ (- (float-time tomorrow-morning) (float-time now)) 60))
+ ;; Create event manually since test-chime-make-event-item uses relative time
+ (event `((title . "Transit to Meeting")
+ (times . ())))
+ (time-info (cons (test-timestamp-string tomorrow-morning) tomorrow-morning))
+ (event-item (list event time-info minutes-until))
+ (upcoming (list event-item))
+ (result (chime--group-events-by-day upcoming)))
+ ;; Verify it's less than 1440 minutes (this is why the bug happens)
+ (should (< minutes-until 1440))
+ ;; Should have 1 group
+ (should (= 1 (length result)))
+ ;; BUG: Currently groups as "Today" but should be "Tomorrow"
+ ;; because the event is on Nov 03, not Nov 02
+ (should (string-match-p "Tomorrow" (car (car result))))))
+ (test-chime-group-events-by-day-teardown)))
+
+;;; Error Cases
+
+(ert-deftest test-chime-group-events-by-day-error-nil-input ()
+ "Test that nil input doesn't crash.
+
+REFACTORED: No timestamps used"
+ (test-chime-group-events-by-day-setup)
+ (unwind-protect
+ (progn
+ ;; Should not crash with nil
+ (should-not (condition-case nil
+ (progn (chime--group-events-by-day nil) nil)
+ (error t))))
+ (test-chime-group-events-by-day-teardown)))
+
+(provide 'test-chime-group-events-by-day)
+;;; test-chime-group-events-by-day.el ends here