diff options
| author | Christian Cleberg <[email protected]> | 2026-07-15 23:27:03 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-07-15 23:27:03 -0500 |
| commit | 0ad430c79eedac4140680e3aaca238969ac711b1 (patch) | |
| tree | e4928ae266acb2282a12e8212b82635890f50089 /HutchTests/InboxViewModelTests.swift | |
| parent | 922502a2c74c66034f3ec2db6612f2a36d242042 (diff) | |
| parent | 97e8b49fcb56751fa0e80a332484db8252753417 (diff) | |
| download | hutch-0ad430c79eedac4140680e3aaca238969ac711b1.tar.gz hutch-0ad430c79eedac4140680e3aaca238969ac711b1.tar.bz2 hutch-0ad430c79eedac4140680e3aaca238969ac711b1.zip | |
Merge pull request #5 from zerolabsco/inbox-unread-baseline
Start a new account at zero unread
Diffstat (limited to 'HutchTests/InboxViewModelTests.swift')
| -rw-r--r-- | HutchTests/InboxViewModelTests.swift | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/HutchTests/InboxViewModelTests.swift b/HutchTests/InboxViewModelTests.swift index e67d317..79cf54c 100644 --- a/HutchTests/InboxViewModelTests.swift +++ b/HutchTests/InboxViewModelTests.swift @@ -42,6 +42,110 @@ struct InboxViewModelTests { } @Test + func freshAccountTreatsExistingMailAsRead() { + let suiteName = "InboxViewModelTests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suiteName)! + defer { defaults.removePersistentDomain(forName: suiteName) } + + let signIn = Date(timeIntervalSince1970: 5_000) + InboxReadStateStore.establishBaselineIfNeeded(now: signIn, defaults: defaults) + + // Years of list history should not land on a new user as unread. + #expect( + !InboxReadStateStore.isUnread( + threadID: "list#old", + lastActivityAt: Date(timeIntervalSince1970: 4_000), + defaults: defaults + ) + ) + } + + @Test + func mailArrivingAfterSignInIsUnread() { + let suiteName = "InboxViewModelTests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suiteName)! + defer { defaults.removePersistentDomain(forName: suiteName) } + + InboxReadStateStore.establishBaselineIfNeeded(now: Date(timeIntervalSince1970: 5_000), defaults: defaults) + + #expect( + InboxReadStateStore.isUnread( + threadID: "list#new", + lastActivityAt: Date(timeIntervalSince1970: 6_000), + defaults: defaults + ) + ) + } + + @Test + func mailExactlyAtTheBaselineIsRead() { + let suiteName = "InboxViewModelTests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suiteName)! + defer { defaults.removePersistentDomain(forName: suiteName) } + + let signIn = Date(timeIntervalSince1970: 5_000) + InboxReadStateStore.establishBaselineIfNeeded(now: signIn, defaults: defaults) + + #expect(!InboxReadStateStore.isUnread(threadID: "list#edge", lastActivityAt: signIn, defaults: defaults)) + } + + @Test + func baselineIsEstablishedOnceAndNotMovedBySubsequentSignIns() { + let suiteName = "InboxViewModelTests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suiteName)! + defer { defaults.removePersistentDomain(forName: suiteName) } + + InboxReadStateStore.establishBaselineIfNeeded(now: Date(timeIntervalSince1970: 5_000), defaults: defaults) + // A later launch must not silently mark the backlog read. + InboxReadStateStore.establishBaselineIfNeeded(now: Date(timeIntervalSince1970: 9_000), defaults: defaults) + + #expect( + InboxReadStateStore.isUnread( + threadID: "list#since", + lastActivityAt: Date(timeIntervalSince1970: 6_000), + defaults: defaults + ) + ) + } + + @Test + func existingAccountsKeepTheirUnreadBacklog() { + let suiteName = "InboxViewModelTests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suiteName)! + defer { defaults.removePersistentDomain(forName: suiteName) } + + // An account already carrying read state has been in use, so upgrading + // must not retroactively mark everything it had not read as read. + InboxReadStateStore.markViewed(Date(timeIntervalSince1970: 1_000), for: "list#seen", defaults: defaults) + InboxReadStateStore.establishBaselineIfNeeded(now: Date(timeIntervalSince1970: 5_000), defaults: defaults) + + #expect( + InboxReadStateStore.isUnread( + threadID: "list#unseen", + lastActivityAt: Date(timeIntervalSince1970: 4_000), + defaults: defaults + ) + ) + } + + @Test + func markingAnOldThreadUnreadSurvivesTheBaseline() { + let suiteName = "InboxViewModelTests-\(UUID().uuidString)" + let defaults = UserDefaults(suiteName: suiteName)! + defer { defaults.removePersistentDomain(forName: suiteName) } + + InboxReadStateStore.establishBaselineIfNeeded(now: Date(timeIntervalSince1970: 5_000), defaults: defaults) + let oldActivity = Date(timeIntervalSince1970: 4_000) + + #expect(!InboxReadStateStore.isUnread(threadID: "list#old", lastActivityAt: oldActivity, defaults: defaults)) + + // Explicitly marking it unread must stick, rather than falling back to the + // baseline rule and reading as read again. + InboxReadStateStore.markUnread(for: "list#old", defaults: defaults) + #expect(InboxReadStateStore.isUnread(threadID: "list#old", lastActivityAt: oldActivity, defaults: defaults)) + } + + @Test func normalizesThreadSubjectsForDisplay() { let summary = InboxThreadSummary( rootEmailID: 1, |
