Total rebrand across KMM project: - Kotlin package: com.example.casera -> com.tt.honeyDue (dirs + declarations) - Gradle: rootProject.name, namespace, applicationId - Android: manifest, strings.xml (all languages), widget resources - iOS: pbxproj bundle IDs, Info.plist, entitlements, xcconfig - iOS directories: Casera/ -> HoneyDue/, CaseraTests/ -> HoneyDueTests/, etc. - Swift source: all class/struct/enum renames - Deep links: casera:// -> honeydue://, .casera -> .honeydue - App icons replaced with honeyDue honeycomb icon - Domains: casera.treytartt.com -> honeyDue.treytartt.com - Bundle IDs: com.tt.casera -> com.tt.honeyDue - Database table names preserved Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
287 lines
7.0 KiB
Swift
287 lines
7.0 KiB
Swift
//
|
|
// DateUtilsTests.swift
|
|
// honeyDueTests
|
|
//
|
|
// Unit tests for DateUtils formatting, parsing, and timezone utilities.
|
|
//
|
|
|
|
import Testing
|
|
import Foundation
|
|
@testable import honeyDue
|
|
|
|
// 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())
|
|
}
|
|
}
|