~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain-ios

1 collaborator
0
1
main
83 lines · 2.9 KB Raw History
@testable import Grain
import XCTest

final class DateFormattingTests: GrainTestCase {
    // MARK: - parse()

    func testParseFractionalSeconds() {
        let date = DateFormatting.parse("2024-06-15T12:30:45.123Z")
        XCTAssertNotNil(date)
    }

    func testParseWithoutFractionalSeconds() {
        let date = DateFormatting.parse("2024-06-15T12:30:45Z")
        XCTAssertNotNil(date)
    }

    func testParseInvalidStringReturnsNil() {
        XCTAssertNil(DateFormatting.parse("not-a-date"))
        XCTAssertNil(DateFormatting.parse(""))
        XCTAssertNil(DateFormatting.parse("2024-13-40"))
    }

    func testParseRoundTrip() throws {
        // Generate an ISO string, parse it back, verify it's close to now
        let iso = DateFormatting.nowISO()
        let parsed = DateFormatting.parse(iso)
        XCTAssertNotNil(parsed)
        // Should be within 1 second of now
        let interval = try abs(XCTUnwrap(parsed?.timeIntervalSinceNow))
        XCTAssertLessThan(interval, 1.0)
    }

    // MARK: - relativeTime()

    func testRelativeTimeNow() {
        let iso = DateFormatting.nowISO()
        let result = DateFormatting.relativeTime(iso)
        XCTAssertEqual(result, "now")
    }

    func testRelativeTimeInvalidReturnsEmpty() {
        XCTAssertEqual(DateFormatting.relativeTime("garbage"), "")
    }

    /// Offsets sit inside their bucket rather than exactly on its edge.
    /// `relativeTime` floors, and the ISO round-trip is only millisecond-precise,
    /// so a boundary value can land a hair short and report the bucket below.
    func testRelativeTimeMinutesAgo() {
        let fiveMinutesAgo = Date().addingTimeInterval(-330) // 5.5 minutes, well within the 5m bucket
        let iso = isoString(from: fiveMinutesAgo)
        let result = DateFormatting.relativeTime(iso)
        XCTAssertEqual(result, "5m")
    }

    func testRelativeTimeHoursAgo() {
        let threeHoursAgo = Date().addingTimeInterval(-12600) // 3.5 hours, well within the 3h bucket
        let iso = isoString(from: threeHoursAgo)
        let result = DateFormatting.relativeTime(iso)
        XCTAssertEqual(result, "3h")
    }

    func testRelativeTimeDaysAgo() {
        let twoDaysAgo = Date().addingTimeInterval(-180_000) // 50 hours, well within the 2d bucket
        let iso = isoString(from: twoDaysAgo)
        let result = DateFormatting.relativeTime(iso)
        XCTAssertEqual(result, "2d")
    }

    func testRelativeTimeWeeksAgo() {
        let twoWeeksAgo = Date().addingTimeInterval(-1_300_000) // ~2.17 weeks, well within the 2w bucket
        let iso = isoString(from: twoWeeksAgo)
        let result = DateFormatting.relativeTime(iso)
        XCTAssertEqual(result, "2w")
    }

    // MARK: - Helpers

    private func isoString(from date: Date) -> String {
        let formatter = ISO8601DateFormatter()
        formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
        return formatter.string(from: date)
    }
}