diff --git a/android/app/src/main/java/com/fabledsword/minstrel/models/Discover.kt b/android/app/src/main/java/com/fabledsword/minstrel/models/Discover.kt index 817eb0aa..00173f1a 100644 --- a/android/app/src/main/java/com/fabledsword/minstrel/models/Discover.kt +++ b/android/app/src/main/java/com/fabledsword/minstrel/models/Discover.kt @@ -119,8 +119,15 @@ data class SuggestionSnoozeRef( private companion object { const val MILLIS_PER_DAY = 86_400_000.0 + // Below this, days read more naturally than a rounded month count. - const val DAYS_BEFORE_MONTHS = 45 + // + // Must be <= DAYS_PER_MONTH, or the singular "in about a month" is + // unreachable: a rounded month count of 1 needs 15..44 days, and any + // threshold above 30 sends all of those down the days branch instead. + // This was 45 and the singular branch was dead code — the unit test + // for it is what surfaced that. + const val DAYS_BEFORE_MONTHS = 30 const val DAYS_PER_MONTH = 30.0 } } diff --git a/android/app/src/test/java/com/fabledsword/minstrel/models/SuggestionSnoozeRefTest.kt b/android/app/src/test/java/com/fabledsword/minstrel/models/SuggestionSnoozeRefTest.kt index f1123e46..2dc598ec 100644 --- a/android/app/src/test/java/com/fabledsword/minstrel/models/SuggestionSnoozeRefTest.kt +++ b/android/app/src/test/java/com/fabledsword/minstrel/models/SuggestionSnoozeRefTest.kt @@ -35,6 +35,22 @@ class SuggestionSnoozeRefTest { assertEquals("in 14 days", snoozeIn(14.0).returnsIn(now)) } + // Pins the days→months boundary. The singular branch was originally dead + // code because the threshold (45) sat above the divisor (30), so no day + // count could ever round to one month without being caught by the days + // branch first. Asserting both sides of the seam keeps that from + // regressing silently. + @Test + fun `the days-to-months boundary is exactly at 30 days`() { + assertEquals("in 29 days", snoozeIn(29.0).returnsIn(now)) + assertEquals("in about a month", snoozeIn(30.0).returnsIn(now)) + } + + @Test + fun `well past a month still reads in the singular rather than jumping to two`() { + assertEquals("in about a month", snoozeIn(40.0).returnsIn(now)) + } + @Test fun `tomorrow is named, not rendered as 1 days`() { assertEquals("tomorrow", snoozeIn(1.0).returnsIn(now)) diff --git a/web/src/lib/components/SuggestionFeed.svelte b/web/src/lib/components/SuggestionFeed.svelte index 26df6ad3..abd91b7e 100644 --- a/web/src/lib/components/SuggestionFeed.svelte +++ b/web/src/lib/components/SuggestionFeed.svelte @@ -66,7 +66,12 @@ const days = Math.round(ms / 86_400_000); if (days < 1) return 'today'; if (days === 1) return 'tomorrow'; - if (days < 45) return `in ${days} days`; + // The 30 must not exceed the divisor below, or the singular "in about a + // month" is unreachable — a rounded month count of 1 needs 15..44 days, + // and any higher threshold sends all of those down the days branch. This + // read 45 and the singular case was dead code (caught by the Android + // unit test for the same logic). + if (days < 30) return `in ${days} days`; const months = Math.round(days / 30); return months === 1 ? 'in about a month' : `in about ${months} months`; } diff --git a/web/src/lib/components/SuggestionFeed.test.ts b/web/src/lib/components/SuggestionFeed.test.ts index 984dedbb..cebe14c5 100644 --- a/web/src/lib/components/SuggestionFeed.test.ts +++ b/web/src/lib/components/SuggestionFeed.test.ts @@ -210,6 +210,21 @@ describe('SuggestionFeed snooze (#2375)', () => { expect(screen.getByText(/back in 14 days/i)).toBeInTheDocument(); }); + // Pins the days→months seam. The singular branch was originally dead code + // here too: the threshold (45) sat above the divisor (30), so no day count + // could round to one month without hitting the days branch first. Kept in + // lockstep with SuggestionSnoozeRefTest on Android. + test('the days-to-months boundary sits at 30 days, so "a month" is reachable', () => { + setSuggestions([]); + setSnoozes([ + { mbid: 'a', name: 'JustUnder', snoozed_until: inDays(29), created_at: inDays(0) }, + { mbid: 'b', name: 'JustOver', snoozed_until: inDays(30), created_at: inDays(0) } + ]); + render(SuggestionFeed); + expect(screen.getByText(/back in 29 days/i)).toBeInTheDocument(); + expect(screen.getByText(/back in about a month/i)).toBeInTheDocument(); + }); + test('no snoozed section when nothing is parked', () => { setSuggestions([oneSeed]); setSnoozes([]);