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.
|
* - 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.
|
* - Manual notes are accepted as already-encrypted ciphertext; this object does not encrypt.
|
||||||
* - Tags are built from category, source type, and date context only.
|
* - 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 {
|
object MemoryCapsuleGenerator {
|
||||||
|
|
||||||
|
|
@ -67,7 +71,8 @@ object MemoryCapsuleGenerator {
|
||||||
event: MemoryDateIdeaEvent,
|
event: MemoryDateIdeaEvent,
|
||||||
noteCiphertext: String? = null,
|
noteCiphertext: String? = null,
|
||||||
photoStoragePath: String? = null,
|
photoStoragePath: String? = null,
|
||||||
now: LocalDate = LocalDate.now()
|
now: LocalDate = LocalDate.now(),
|
||||||
|
createdAtMillis: Long = System.currentTimeMillis()
|
||||||
): MemoryCapsule {
|
): MemoryCapsule {
|
||||||
val date = event.scheduledDate ?: now
|
val date = event.scheduledDate ?: now
|
||||||
val displayCategory = event.category.takeIf { it.isNotBlank() } ?: DATE_CATEGORY
|
val displayCategory = event.category.takeIf { it.isNotBlank() } ?: DATE_CATEGORY
|
||||||
|
|
@ -92,7 +97,7 @@ object MemoryCapsuleGenerator {
|
||||||
),
|
),
|
||||||
source = MemoryCapsuleSource.DATE_IDEA,
|
source = MemoryCapsuleSource.DATE_IDEA,
|
||||||
sourceRefId = event.dateIdeaId,
|
sourceRefId = event.dateIdeaId,
|
||||||
createdAt = System.currentTimeMillis()
|
createdAt = createdAtMillis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,7 +111,8 @@ object MemoryCapsuleGenerator {
|
||||||
authorId: String,
|
authorId: String,
|
||||||
event: MemoryRevealEvent,
|
event: MemoryRevealEvent,
|
||||||
noteCiphertext: String? = null,
|
noteCiphertext: String? = null,
|
||||||
photoStoragePath: String? = null
|
photoStoragePath: String? = null,
|
||||||
|
createdAtMillis: Long = System.currentTimeMillis()
|
||||||
): MemoryCapsule {
|
): MemoryCapsule {
|
||||||
val displayCategory = event.categoryId?.takeIf { it.isNotBlank() } ?: REVEAL_CATEGORY
|
val displayCategory = event.categoryId?.takeIf { it.isNotBlank() } ?: REVEAL_CATEGORY
|
||||||
val title = "A moment we revealed together${categoryFragment(displayCategory)}"
|
val title = "A moment we revealed together${categoryFragment(displayCategory)}"
|
||||||
|
|
@ -127,7 +133,7 @@ object MemoryCapsuleGenerator {
|
||||||
),
|
),
|
||||||
source = MemoryCapsuleSource.REVEAL,
|
source = MemoryCapsuleSource.REVEAL,
|
||||||
sourceRefId = event.questionId,
|
sourceRefId = event.questionId,
|
||||||
createdAt = System.currentTimeMillis()
|
createdAt = createdAtMillis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,7 +145,8 @@ object MemoryCapsuleGenerator {
|
||||||
authorId: String,
|
authorId: String,
|
||||||
event: MemoryRecapEvent,
|
event: MemoryRecapEvent,
|
||||||
noteCiphertext: String? = null,
|
noteCiphertext: String? = null,
|
||||||
photoStoragePath: String? = null
|
photoStoragePath: String? = null,
|
||||||
|
createdAtMillis: Long = System.currentTimeMillis()
|
||||||
): MemoryCapsule {
|
): MemoryCapsule {
|
||||||
val displayCategory = event.favoriteCategory?.takeIf { it.isNotBlank() } ?: RECAP_CATEGORY
|
val displayCategory = event.favoriteCategory?.takeIf { it.isNotBlank() } ?: RECAP_CATEGORY
|
||||||
val weekNumber = weekNumberLabel(event.weekStart, event.weekEnd)
|
val weekNumber = weekNumberLabel(event.weekStart, event.weekEnd)
|
||||||
|
|
@ -162,7 +169,7 @@ object MemoryCapsuleGenerator {
|
||||||
),
|
),
|
||||||
source = MemoryCapsuleSource.WEEKLY_RECAP,
|
source = MemoryCapsuleSource.WEEKLY_RECAP,
|
||||||
sourceRefId = event.recapId,
|
sourceRefId = event.recapId,
|
||||||
createdAt = System.currentTimeMillis()
|
createdAt = createdAtMillis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,7 +181,8 @@ object MemoryCapsuleGenerator {
|
||||||
authorId: String,
|
authorId: String,
|
||||||
event: MemoryChallengeEvent,
|
event: MemoryChallengeEvent,
|
||||||
noteCiphertext: String? = null,
|
noteCiphertext: String? = null,
|
||||||
photoStoragePath: String? = null
|
photoStoragePath: String? = null,
|
||||||
|
createdAtMillis: Long = System.currentTimeMillis()
|
||||||
): MemoryCapsule {
|
): MemoryCapsule {
|
||||||
val displayCategory = event.challengeCategory?.takeIf { it.isNotBlank() } ?: CHALLENGE_CATEGORY
|
val displayCategory = event.challengeCategory?.takeIf { it.isNotBlank() } ?: CHALLENGE_CATEGORY
|
||||||
val title = "Challenge completed${categoryFragment(displayCategory)}"
|
val title = "Challenge completed${categoryFragment(displayCategory)}"
|
||||||
|
|
@ -195,7 +203,7 @@ object MemoryCapsuleGenerator {
|
||||||
),
|
),
|
||||||
source = MemoryCapsuleSource.CHALLENGE,
|
source = MemoryCapsuleSource.CHALLENGE,
|
||||||
sourceRefId = event.challengeId,
|
sourceRefId = event.challengeId,
|
||||||
createdAt = System.currentTimeMillis()
|
createdAt = createdAtMillis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -209,7 +217,8 @@ object MemoryCapsuleGenerator {
|
||||||
coupleId: String,
|
coupleId: String,
|
||||||
authorId: String,
|
authorId: String,
|
||||||
input: MemoryManualInput,
|
input: MemoryManualInput,
|
||||||
now: LocalDate = LocalDate.now()
|
now: LocalDate = LocalDate.now(),
|
||||||
|
createdAtMillis: Long = System.currentTimeMillis()
|
||||||
): MemoryCapsule {
|
): MemoryCapsule {
|
||||||
val displayCategory = input.category.takeIf { it.isNotBlank() } ?: DEFAULT_CATEGORY
|
val displayCategory = input.category.takeIf { it.isNotBlank() } ?: DEFAULT_CATEGORY
|
||||||
val title = input.title.takeIf { it.isNotBlank() }
|
val title = input.title.takeIf { it.isNotBlank() }
|
||||||
|
|
@ -231,7 +240,7 @@ object MemoryCapsuleGenerator {
|
||||||
now = now
|
now = now
|
||||||
),
|
),
|
||||||
source = MemoryCapsuleSource.MANUAL,
|
source = MemoryCapsuleSource.MANUAL,
|
||||||
createdAt = System.currentTimeMillis()
|
createdAt = createdAtMillis
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,8 +425,11 @@ class MemoryCapsuleGeneratorTest {
|
||||||
scheduledDate = today
|
scheduledDate = today
|
||||||
)
|
)
|
||||||
|
|
||||||
val first = MemoryCapsuleGenerator.fromDateIdea(coupleId, authorId, event, now = today)
|
// Pin the clock: the generator documents itself as pure/deterministic, so identical inputs
|
||||||
val second = MemoryCapsuleGenerator.fromDateIdea(coupleId, authorId, event, now = today)
|
// (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)
|
assertEquals(first, second)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue