-- Unit tests for date parsing and formatting utilities local date_utils = require('notex.utils.date') describe("date utilities", function() describe("parse_date", function() it("should parse ISO 8601 dates", function() local timestamp = date_utils.parse_date("2023-12-25") assert.is_not_nil(timestamp) local formatted = os.date("%Y-%m-%d", timestamp) assert.equals("2023-12-25", formatted) end) it("should parse ISO 8601 datetimes", function() local timestamp = date_utils.parse_date("2023-12-25T10:30:00") assert.is_not_nil(timestamp) local formatted = os.date("%Y-%m-%d %H:%M:%S", timestamp) assert.equals("2023-12-25 10:30:00", formatted) end) it("should parse ISO 8601 with timezone", function() local timestamp = date_utils.parse_date("2023-12-25T10:30:00+02:00") assert.is_not_nil(timestamp) -- Should be converted to UTC local utc_formatted = os.date("%Y-%m-%d %H:%M:%S", timestamp) assert.equals("2023-12-25 08:30:00", utc_formatted) end) it("should parse relative dates", function() -- Test 1 day ago local one_day_ago = os.time() - 86400 local timestamp = date_utils.parse_date("1d") assert.is_true(math.abs(timestamp - one_day_ago) < 60) -- Within 1 minute -- Test 1 hour ago local one_hour_ago = os.time() - 3600 timestamp = date_utils.parse_date("1h") assert.is_true(math.abs(timestamp - one_hour_ago) < 60) -- Within 1 minute end) it("should parse natural dates", function() local timestamp = date_utils.parse_date("2023-12-25") assert.is_not_nil(timestamp) local formatted = os.date("%Y-%m-%d", timestamp) assert.equals("2023-12-25", formatted) end) it("should return nil for invalid dates", function() local timestamp = date_utils.parse_date("invalid date") assert.is_nil(timestamp) timestamp = date_utils.parse_date("") assert.is_nil(timestamp) timestamp = date_utils.parse_date(nil) assert.is_nil(timestamp) end) it("should parse common date formats", function() -- MM/DD/YYYY local timestamp = date_utils.parse_date("12/25/2023") assert.is_not_nil(timestamp) -- MM-DD-YYYY timestamp = date_utils.parse_date("12-25-2023") assert.is_not_nil(timestamp) end) end) describe("format_date", function() it("should format timestamp to string", function() local timestamp = os.time({year = 2023, month = 12, day = 25, hour = 10, min = 30, sec = 0}) local formatted = date_utils.format_date(timestamp, "%Y-%m-%d %H:%M:%S") assert.equals("2023-12-25 10:30:00", formatted) end) it("should use default format", function() local timestamp = os.time({year = 2023, month = 12, day = 25}) local formatted = date_utils.format_date(timestamp) assert.equals("2023-12-25", formatted) end) it("should handle nil timestamp", function() local formatted = date_utils.format_date(nil) assert.equals("", formatted) end) end) describe("get_relative_time", function() it("should return 'just now' for recent times", function() local current_time = os.time() local relative = date_utils.get_relative_time(current_time) assert.equals("just now", relative) end) it("should return minutes ago", function() local timestamp = os.time() - 120 -- 2 minutes ago local relative = date_utils.get_relative_time(timestamp) assert.equals("2 minutes ago", relative) end) it("should return hours ago", function() local timestamp = os.time() - 7200 -- 2 hours ago local relative = date_utils.get_relative_time(timestamp) assert.equals("2 hours ago", relative) end) it("should return days ago", function() local timestamp = os.time() - 172800 -- 2 days ago local relative = date_utils.get_relative_time(timestamp) assert.equals("2 days ago", relative) end) it("should return months ago", function() local timestamp = os.time() - (60 * 86400) -- ~2 months ago local relative = date_utils.get_relative_time(timestamp) assert.matches("months ago", relative) end) it("should return years ago", function() local timestamp = os.time() - (365 * 86400) -- ~1 year ago local relative = date_utils.get_relative_time(timestamp) assert.matches("year ago", relative) end) it("should handle singular forms", function() local timestamp = os.time() - 60 -- 1 minute ago local relative = date_utils.get_relative_time(timestamp) assert.equals("1 minute ago", relative) timestamp = os.time() - 3600 -- 1 hour ago relative = date_utils.get_relative_time(timestamp) assert.equals("1 hour ago", relative) end) end) describe("get_month_number", function() it("should convert month names to numbers", function() assert.equals(1, date_utils.get_month_number("January")) assert.equals(12, date_utils.get_month_number("December")) assert.equals(6, date_utils.get_month_number("June")) end) it("should handle short month names", function() assert.equals(1, date_utils.get_month_number("Jan")) assert.equals(12, date_utils.get_month_number("Dec")) assert.equals(6, date_utils.get_month_number("Jun")) end) it("should be case insensitive", function() assert.equals(1, date_utils.get_month_number("JANUARY")) assert.equals(1, date_utils.get_month_number("january")) assert.equals(1, date_utils.get_month_number("jan")) end) it("should return nil for invalid month names", function() assert.is_nil(date_utils.get_month_number("NotAMonth")) assert.is_nil(date_utils.get_month_number("")) end) end) describe("get_month_name", function() it("should convert month numbers to names", function() assert.equals("January", date_utils.get_month_name(1)) assert.equals("December", date_utils.get_month_name(12)) assert.equals("June", date_utils.get_month_name(6)) end) it("should return short names when requested", function() assert.equals("Jan", date_utils.get_month_name(1, true)) assert.equals("Dec", date_utils.get_month_name(12, true)) assert.equals("Jun", date_utils.get_month_name(6, true)) end) it("should return nil for invalid month numbers", function() assert.is_nil(date_utils.get_month_name(0)) assert.is_nil(date_utils.get_month_name(13)) assert.is_nil(date_utils.get_month_name(-1)) end) end) describe("is_valid_date", function() it("should validate correct dates", function() assert.is_true(date_utils.is_valid_date("2023-12-25")) assert.is_true(date_utils.is_valid_date("2023-12-25T10:30:00")) assert.is_true(date_utils.is_valid_date("1d")) end) it("should reject invalid dates", function() assert.is_false(date_utils.is_valid_date("invalid")) assert.is_false(date_utils.is_valid_date("")) assert.is_false(date_utils.is_valid_date(nil)) end) end) describe("add_time", function() it("should add time to timestamp", function() local timestamp = os.time({year = 2023, month = 12, day = 25}) local new_timestamp = date_utils.add_time(timestamp, 1, "days") local expected = os.time({year = 2023, month = 12, day = 26}) assert.equals(expected, new_timestamp) end) it("should add different time units", function() local timestamp = os.time({year = 2023, month = 12, day = 25, hour = 10}) -- Add hours local new_timestamp = date_utils.add_time(timestamp, 2, "hours") local expected = os.time({year = 2023, month = 12, day = 25, hour = 12}) assert.equals(expected, new_timestamp) -- Add minutes new_timestamp = date_utils.add_time(timestamp, 30, "minutes") expected = os.time({year = 2023, month = 12, day = 25, hour = 10, min = 30}) assert.equals(expected, new_timestamp) end) end) describe("get_date_range", function() it("should calculate date range", function() local range = date_utils.get_date_range("2023-12-25", "2023-12-27") assert.is_not_nil(range) assert.equals(2, range.duration_days) assert.equals("2023-12-25", range.start_formatted) assert.equals("2023-12-27", range.end_formatted) end) it("should return nil for invalid dates", function() local range = date_utils.get_date_range("invalid", "2023-12-27") assert.is_nil(range) end) end) describe("get_week_bounds", function() it("should get week start and end", function() local week_bounds = date_utils.get_week_bounds() assert.is_not_nil(week_bounds.start_timestamp) assert.is_not_nil(week_bounds.end_timestamp) assert.is_not_nil(week_bounds.start_formatted) assert.is_not_nil(week_bounds.end_formatted) -- Should be 7 days apart local duration = week_bounds.end_timestamp - week_bounds.start_timestamp assert.equals(6 * 86400, duration) -- 6 days in seconds end) end) describe("get_month_bounds", function() it("should get month start and end", function() local month_bounds = date_utils.get_month_bounds(os.time({year = 2023, month = 12, day = 15})) assert.is_not_nil(month_bounds.start_timestamp) assert.is_not_nil(month_bounds.end_timestamp) assert.equals("2023-12-01", month_bounds.start_formatted) assert.equals("2023-12-31", month_bounds.end_formatted) end) end) describe("get_timezones", function() it("should return list of timezones", function() local timezones = date_utils.get_timezones() assert.is_table(timezones) assert.is_true(#timezones > 0) assert.is_true(vim.tbl_contains(timezones, "UTC")) assert.is_true(vim.tbl_contains(timezones, "America/New_York")) end) end) end)