// // DateUtilsTests.swift // CaseraTests // // Unit tests for DateUtils formatting, parsing, and timezone utilities. // import Testing import Foundation @testable import Casera // MARK: - DateUtils.formatDate Tests struct DateUtilsFormatDateTests { @Test func todayReturnsToday() { let today = DateUtils.todayString() let result = DateUtils.formatDate(today) #expect(result == "Today") } @Test func nilReturnsEmpty() { let result = DateUtils.formatDate(nil) #expect(result == "") } @Test func emptyReturnsEmpty() { let result = DateUtils.formatDate("") #expect(result == "") } @Test func invalidDateReturnsSelf() { let result = DateUtils.formatDate("not-a-date") #expect(result == "not-a-date") } @Test func dateWithTimePartExtractsDate() { let today = DateUtils.todayString() let result = DateUtils.formatDate("\(today)T12:00:00Z") #expect(result == "Today") } } // MARK: - DateUtils.formatDateMedium Tests struct DateUtilsFormatDateMediumTests { @Test func validDateFormatsAsMedium() { let result = DateUtils.formatDateMedium("2024-01-15") #expect(result == "Jan 15, 2024") } @Test func nilReturnsEmpty() { let result = DateUtils.formatDateMedium(nil) #expect(result == "") } @Test func invalidDateReturnsSelf() { let result = DateUtils.formatDateMedium("bad-date") #expect(result == "bad-date") } } // MARK: - DateUtils.isOverdue Tests struct DateUtilsIsOverdueTests { @Test func pastDateIsOverdue() { let result = DateUtils.isOverdue("2020-01-01") #expect(result == true) } @Test func futureDateIsNotOverdue() { let result = DateUtils.isOverdue("2099-12-31") #expect(result == false) } @Test func nilIsNotOverdue() { let result = DateUtils.isOverdue(nil) #expect(result == false) } @Test func emptyIsNotOverdue() { let result = DateUtils.isOverdue("") #expect(result == false) } @Test func todayIsNotOverdue() { let today = DateUtils.todayString() let result = DateUtils.isOverdue(today) #expect(result == false) } } // MARK: - DateUtils.parseDate Tests struct DateUtilsParseDateTests { @Test func validDateStringParsed() { let date = DateUtils.parseDate("2024-06-15") #expect(date != nil) } @Test func nilReturnsNil() { let date = DateUtils.parseDate(nil) #expect(date == nil) } @Test func emptyReturnsNil() { let date = DateUtils.parseDate("") #expect(date == nil) } @Test func invalidReturnsNil() { let date = DateUtils.parseDate("not-a-date") #expect(date == nil) } @Test func dateTimeStringExtractsDate() { let date = DateUtils.parseDate("2024-06-15T10:30:00Z") #expect(date != nil) } } // MARK: - DateUtils.formatHour Tests struct DateUtilsFormatHourTests { @Test func midnightFormatsCorrectly() { #expect(DateUtils.formatHour(0) == "12:00 AM") } @Test func morningFormatsCorrectly() { #expect(DateUtils.formatHour(8) == "8:00 AM") } @Test func noonFormatsCorrectly() { #expect(DateUtils.formatHour(12) == "12:00 PM") } @Test func afternoonFormatsCorrectly() { #expect(DateUtils.formatHour(14) == "2:00 PM") } @Test func elevenPMFormatsCorrectly() { #expect(DateUtils.formatHour(23) == "11:00 PM") } @Test func oneAMFormatsCorrectly() { #expect(DateUtils.formatHour(1) == "1:00 AM") } @Test func elevenAMFormatsCorrectly() { #expect(DateUtils.formatHour(11) == "11:00 AM") } @Test func onePMFormatsCorrectly() { #expect(DateUtils.formatHour(13) == "1:00 PM") } } // MARK: - DateUtils.formatRelativeDate Tests struct DateUtilsFormatRelativeDateTests { @Test func nilReturnsEmpty() { let result = DateUtils.formatRelativeDate(nil) #expect(result == "") } @Test func emptyReturnsEmpty() { let result = DateUtils.formatRelativeDate("") #expect(result == "") } @Test func todayReturnsToday() { let today = DateUtils.todayString() let result = DateUtils.formatRelativeDate(today) #expect(result == "Today") } @Test func invalidReturnsSelf() { let result = DateUtils.formatRelativeDate("bad") #expect(result == "bad") } } // MARK: - DateUtils.localHourToUtc / utcHourToLocal Round-Trip Tests struct TimezoneConversionTests { @Test func roundTripLocalToUtcToLocal() { let localHour = 10 let utc = DateUtils.localHourToUtc(localHour) let backToLocal = DateUtils.utcHourToLocal(utc) #expect(backToLocal == localHour) } @Test func utcAndLocalDifferByTimezoneOffset() { // Just verify it returns a value in 0-23 range let utc = DateUtils.localHourToUtc(15) #expect(utc >= 0 && utc <= 23) } } // MARK: - DateExtensions Tests struct DateExtensionsTests { @Test func todayIsToday() { #expect(Date().isToday) } @Test func todayRelativeDescriptionIsToday() { #expect(Date().relativeDescription == "Today") } @Test func apiFormatHasCorrectPattern() { let formatted = Date().formattedAPI() // Should match yyyy-MM-dd pattern let parts = formatted.split(separator: "-") #expect(parts.count == 3) #expect(parts[0].count == 4) #expect(parts[1].count == 2) #expect(parts[2].count == 2) } @Test func distantPastIsPast() { let past = Date.distantPast #expect(past.isPast) } @Test func distantFutureIsNotPast() { let future = Date.distantFuture #expect(!future.isPast) } } // MARK: - String Date Extension Tests struct StringDateExtensionTests { @Test func validAPIDateParsed() { let date = "2024-06-15".toDate() #expect(date != nil) } @Test func invalidDateReturnsNil() { let date = "invalid".toDate() #expect(date == nil) } @Test func dateTimeStringParsed() { let date = "2024-06-15T10:30:00Z".toDate() #expect(date != nil) } @Test func pastDateIsOverdue() { #expect("2020-01-01".isOverdue()) } @Test func futureDateIsNotOverdue() { #expect(!"2099-12-31".isOverdue()) } @Test func toFormattedDateReturnsFormatted() { let result = "2024-01-15".toFormattedDate() #expect(result == "Jan 15, 2024") } @Test func invalidDateToFormattedReturnsSelf() { let result = "bad-date".toFormattedDate() #expect(result == "bad-date") } } // MARK: - Helper for date tests private extension DateUtils { /// Returns today's date as an API-formatted string (yyyy-MM-dd) static func todayString() -> String { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter.string(from: Date()) } }