From f117da16c805b8db3a2be9436043750cdf58b631 Mon Sep 17 00:00:00 2001 From: null Date: Wed, 1 Jul 2026 00:21:42 -0500 Subject: [PATCH] test(home): 10 unit tests for computeDailyQuestionState --- .../closer/ui/home/DailyQuestionStateTest.kt | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 app/src/test/java/app/closer/ui/home/DailyQuestionStateTest.kt diff --git a/app/src/test/java/app/closer/ui/home/DailyQuestionStateTest.kt b/app/src/test/java/app/closer/ui/home/DailyQuestionStateTest.kt new file mode 100644 index 00000000..770d7a93 --- /dev/null +++ b/app/src/test/java/app/closer/ui/home/DailyQuestionStateTest.kt @@ -0,0 +1,132 @@ +package app.closer.ui.home + +import app.closer.domain.model.LocalAnswer +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Covers [computeDailyQuestionState] — in particular the reveal-waiting (BOTH_ANSWERED) gating that + * drives the Home hero + "Your reveal is waiting" art. The key behavior: the partner only counts as + * "answered" when their answer is for THIS question, not just any answer for today's date. + */ +class DailyQuestionStateTest { + + private fun revealedAnswer(questionId: String) = LocalAnswer( + questionId = questionId, + questionText = "q", + category = "cat", + answerType = "text", + isRevealed = true + ) + + @Test + fun `you answered first then partner answers the same question is reveal-waiting`() { + val state = computeDailyQuestionState( + questionId = "q1", + answeredQuestionIds = setOf("q1"), + latestAnswer = null, + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "q1" + ) + assertEquals(DailyQuestionState.BOTH_ANSWERED, state) + } + + @Test + fun `partner answered a different question does not trigger reveal-waiting`() { + // Daily question rotated to q2; the partner's today-doc is still for q1. Must NOT be both-answered. + val state = computeDailyQuestionState( + questionId = "q2", + answeredQuestionIds = setOf("q2"), + latestAnswer = null, + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "q1" + ) + assertEquals(DailyQuestionState.USER_ANSWERED_PARTNER_PENDING, state) + } + + @Test + fun `legacy answer doc without a question id falls back to existence`() { + // Blank partner question id (pre-field answer doc) must not regress the common case. + val state = computeDailyQuestionState( + questionId = "q1", + answeredQuestionIds = setOf("q1"), + latestAnswer = null, + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "" + ) + assertEquals(DailyQuestionState.BOTH_ANSWERED, state) + } + + @Test + fun `you answered and partner has not is awaiting-partner`() { + val state = computeDailyQuestionState( + questionId = "q1", + answeredQuestionIds = setOf("q1"), + latestAnswer = null, + hasPartnerAnsweredToday = false, + partnerAnsweredQuestionId = null + ) + assertEquals(DailyQuestionState.USER_ANSWERED_PARTNER_PENDING, state) + } + + @Test + fun `partner answered this question and you have not is your-turn`() { + val state = computeDailyQuestionState( + questionId = "q1", + answeredQuestionIds = emptySet(), + latestAnswer = null, + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "q1" + ) + assertEquals(DailyQuestionState.PARTNER_ANSWERED_USER_PENDING, state) + } + + @Test + fun `partner answered a different question and you have not is unanswered`() { + val state = computeDailyQuestionState( + questionId = "q2", + answeredQuestionIds = emptySet(), + latestAnswer = null, + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "q1" + ) + assertEquals(DailyQuestionState.UNANSWERED, state) + } + + @Test + fun `revealing this question takes precedence over both-answered`() { + val state = computeDailyQuestionState( + questionId = "q1", + answeredQuestionIds = setOf("q1"), + latestAnswer = revealedAnswer("q1"), + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "q1" + ) + assertEquals(DailyQuestionState.REVEALED, state) + } + + @Test + fun `no assigned question is unanswered`() { + val state = computeDailyQuestionState( + questionId = null, + answeredQuestionIds = setOf("q1"), + latestAnswer = null, + hasPartnerAnsweredToday = true, + partnerAnsweredQuestionId = "q1" + ) + assertEquals(DailyQuestionState.UNANSWERED, state) + } + + @Test + fun `a revealed answer for a stale question does not mask the current unanswered one`() { + // latest answer is for q1 (revealed), but today's question is q2 with no answers yet. + val state = computeDailyQuestionState( + questionId = "q2", + answeredQuestionIds = setOf("q1"), + latestAnswer = revealedAnswer("q1"), + hasPartnerAnsweredToday = false, + partnerAnsweredQuestionId = null + ) + assertEquals(DailyQuestionState.UNANSWERED, state) + } +}