Files
honeyDueKMP/iosApp/CaseraTests/DateUtilsTests.swift
treyt fc0e0688eb Add comprehensive iOS unit and UI test suites for greenfield test plan
- Create unit tests: DataLayerTests (27 tests for DATA-001–007), DataManagerExtendedTests
  (20 tests for TASK-005, TASK-012, TCOMP-003, THEME-001, QA-002), plus ValidationHelpers,
  TaskMetrics, StringExtensions, DoubleExtensions, DateUtils, DocumentHelpers, ErrorMessageParser
- Create UI tests: AuthenticationTests, PasswordResetTests, OnboardingTests, TaskIntegration,
  ContractorIntegration, ResidenceIntegration, DocumentIntegration, DataLayer, Stability
- Add UI test framework: AuthenticatedTestCase, ScreenObjects, TestFlows, TestAccountManager,
  TestAccountAPIClient, TestDataCleaner, TestDataSeeder
- Add accessibility identifiers to password reset views for UI test support
- Add greenfield test plan CSVs and update automated column for 27 test IDs
- All 297 unit tests pass across 60 suites

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 15:37:56 -06:00

287 lines
7.0 KiB
Swift

//
// 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())
}
}