feat(domain): update MemoryCapsuleGenerator + test
This commit is contained in:
parent
b9828b60c5
commit
4ee600125d
|
|
@ -23,6 +23,10 @@ import java.time.temporal.ChronoUnit
|
|||
* - Reveal-derived titles use only category metadata and the fact that a reveal happened.
|
||||
* - Manual notes are accepted as already-encrypted ciphertext; this object does not encrypt.
|
||||
* - Tags are built from category, source type, and date context only.
|
||||
*
|
||||
* Determinism: every factory takes an injectable `createdAtMillis` (defaulting to the wall clock)
|
||||
* so that, given identical inputs, the produced capsule is identical. Tests pin it; production omits
|
||||
* it to stamp the real creation time.
|
||||
*/
|
||||
object MemoryCapsuleGenerator {
|
||||
|
||||
|
|
@ -67,7 +71,8 @@ object MemoryCapsuleGenerator {
|
|||
event: MemoryDateIdeaEvent,
|
||||
noteCiphertext: String? = null,
|
||||
photoStoragePath: String? = null,
|
||||
now: LocalDate = LocalDate.now()
|
||||
now: LocalDate = LocalDate.now(),
|
||||
createdAtMillis: Long = System.currentTimeMillis()
|
||||
): MemoryCapsule {
|
||||
val date = event.scheduledDate ?: now
|
||||
val displayCategory = event.category.takeIf { it.isNotBlank() } ?: DATE_CATEGORY
|
||||
|
|
@ -92,7 +97,7 @@ object MemoryCapsuleGenerator {
|
|||
),
|
||||
source = MemoryCapsuleSource.DATE_IDEA,
|
||||
sourceRefId = event.dateIdeaId,
|
||||
createdAt = System.currentTimeMillis()
|
||||
createdAt = createdAtMillis
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +111,8 @@ object MemoryCapsuleGenerator {
|
|||
authorId: String,
|
||||
event: MemoryRevealEvent,
|
||||
noteCiphertext: String? = null,
|
||||
photoStoragePath: String? = null
|
||||
photoStoragePath: String? = null,
|
||||
createdAtMillis: Long = System.currentTimeMillis()
|
||||
): MemoryCapsule {
|
||||
val displayCategory = event.categoryId?.takeIf { it.isNotBlank() } ?: REVEAL_CATEGORY
|
||||
val title = "A moment we revealed together${categoryFragment(displayCategory)}"
|
||||
|
|
@ -127,7 +133,7 @@ object MemoryCapsuleGenerator {
|
|||
),
|
||||
source = MemoryCapsuleSource.REVEAL,
|
||||
sourceRefId = event.questionId,
|
||||
createdAt = System.currentTimeMillis()
|
||||
createdAt = createdAtMillis
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -139,7 +145,8 @@ object MemoryCapsuleGenerator {
|
|||
authorId: String,
|
||||
event: MemoryRecapEvent,
|
||||
noteCiphertext: String? = null,
|
||||
photoStoragePath: String? = null
|
||||
photoStoragePath: String? = null,
|
||||
createdAtMillis: Long = System.currentTimeMillis()
|
||||
): MemoryCapsule {
|
||||
val displayCategory = event.favoriteCategory?.takeIf { it.isNotBlank() } ?: RECAP_CATEGORY
|
||||
val weekNumber = weekNumberLabel(event.weekStart, event.weekEnd)
|
||||
|
|
@ -162,7 +169,7 @@ object MemoryCapsuleGenerator {
|
|||
),
|
||||
source = MemoryCapsuleSource.WEEKLY_RECAP,
|
||||
sourceRefId = event.recapId,
|
||||
createdAt = System.currentTimeMillis()
|
||||
createdAt = createdAtMillis
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -174,7 +181,8 @@ object MemoryCapsuleGenerator {
|
|||
authorId: String,
|
||||
event: MemoryChallengeEvent,
|
||||
noteCiphertext: String? = null,
|
||||
photoStoragePath: String? = null
|
||||
photoStoragePath: String? = null,
|
||||
createdAtMillis: Long = System.currentTimeMillis()
|
||||
): MemoryCapsule {
|
||||
val displayCategory = event.challengeCategory?.takeIf { it.isNotBlank() } ?: CHALLENGE_CATEGORY
|
||||
val title = "Challenge completed${categoryFragment(displayCategory)}"
|
||||
|
|
@ -195,7 +203,7 @@ object MemoryCapsuleGenerator {
|
|||
),
|
||||
source = MemoryCapsuleSource.CHALLENGE,
|
||||
sourceRefId = event.challengeId,
|
||||
createdAt = System.currentTimeMillis()
|
||||
createdAt = createdAtMillis
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +217,8 @@ object MemoryCapsuleGenerator {
|
|||
coupleId: String,
|
||||
authorId: String,
|
||||
input: MemoryManualInput,
|
||||
now: LocalDate = LocalDate.now()
|
||||
now: LocalDate = LocalDate.now(),
|
||||
createdAtMillis: Long = System.currentTimeMillis()
|
||||
): MemoryCapsule {
|
||||
val displayCategory = input.category.takeIf { it.isNotBlank() } ?: DEFAULT_CATEGORY
|
||||
val title = input.title.takeIf { it.isNotBlank() }
|
||||
|
|
@ -231,7 +240,7 @@ object MemoryCapsuleGenerator {
|
|||
now = now
|
||||
),
|
||||
source = MemoryCapsuleSource.MANUAL,
|
||||
createdAt = System.currentTimeMillis()
|
||||
createdAt = createdAtMillis
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -425,8 +425,11 @@ class MemoryCapsuleGeneratorTest {
|
|||
scheduledDate = today
|
||||
)
|
||||
|
||||
val first = MemoryCapsuleGenerator.fromDateIdea(coupleId, authorId, event, now = today)
|
||||
val second = MemoryCapsuleGenerator.fromDateIdea(coupleId, authorId, event, now = today)
|
||||
// Pin the clock: the generator documents itself as pure/deterministic, so identical inputs
|
||||
// (including createdAtMillis) must yield identical capsules. Without an injected clock the
|
||||
// createdAt timestamp made this flaky across millisecond boundaries.
|
||||
val first = MemoryCapsuleGenerator.fromDateIdea(coupleId, authorId, event, now = today, createdAtMillis = 1_700_000_000_000L)
|
||||
val second = MemoryCapsuleGenerator.fromDateIdea(coupleId, authorId, event, now = today, createdAtMillis = 1_700_000_000_000L)
|
||||
|
||||
assertEquals(first, second)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue