Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-22 19:40:27 +01:00
commit 37694bb2a4
12 changed files with 68 additions and 13 deletions

View file

@ -195,10 +195,12 @@ internal class DefaultAddressBookRepositoryTest {
assertThat(result).isEqualTo(bob)
}
private fun createContact(id: String, name: String): Contact = Contact(
private fun createContact(id: String, name: String, iconColor: String = "KekColor"): Contact = Contact(
id = ContactId(id),
walletId = UserWalletId(WALLET_A),
name = ContactName(name).getOrNull()!!,
icon = "",
iconColor = iconColor,
createdAt = TIMESTAMP,
updatedAt = TIMESTAMP,
addressEntries = emptyList(),

View file

@ -15,6 +15,8 @@ data class Contact(
val id: ContactId,
val walletId: UserWalletId,
val name: ContactName,
val icon: String,
val iconColor: String,
val createdAt: String,
val updatedAt: String,
val addressEntries: List<AddressEntry>,

View file

@ -25,10 +25,10 @@ class CreateContactUseCase(
private val timestampProvider: IsoTimestampProvider,
) {
@Suppress("LongParameterList")
suspend operator fun invoke(
userWallet: UserWallet,
name: String,
iconColor: String,
network: Network,
addressEntries: List<AddressEntry>,
): Either<SaveContactError, Contact> = either {
@ -42,6 +42,8 @@ class CreateContactUseCase(
id = ContactId(UUID.randomUUID().toString()),
walletId = userWalletId,
name = validName,
icon = "",
iconColor = iconColor,
createdAt = now,
updatedAt = now,
addressEntries = addressEntries,

View file

@ -21,6 +21,7 @@ class UpdateContactUseCase(
userWallet: UserWallet,
contact: Contact,
name: String,
iconColor: String,
addressEntries: List<AddressEntry>,
): Either<SaveContactError, Contact> = either {
val validName = ContactName(name)
@ -29,6 +30,7 @@ class UpdateContactUseCase(
val updated = contact.copy(
name = validName,
iconColor = iconColor,
addressEntries = addressEntries,
updatedAt = timestampProvider.now(),
)

View file

@ -36,8 +36,16 @@ internal class AddressBookCipherTest {
fun `GIVEN multi-contact book WHEN encrypt then decrypt THEN original book is restored`() {
// Arrange
val book = addressBook(
contact("Alice", entry("addr-1", "0xabc", memo = "memo")),
contact("Bob", entry("addr-2", "0xdef", memo = null)),
contact(
name = "Alice",
iconColor = "TestColor1",
entries = arrayOf(entry("addr-1", "0xabc", memo = "memo")),
),
contact(
name = "Bob",
iconColor = "TestColor2",
entries = arrayOf(entry("addr-2", "0xdef", memo = null)),
),
)
// Act
@ -64,7 +72,13 @@ internal class AddressBookCipherTest {
@Test
fun `GIVEN a book WHEN encrypt THEN blob metadata and field sizes match the spec`() {
// Arrange
val book = addressBook(contact("Alice", entry("addr-1", "0xabc", memo = null)))
val book = addressBook(
contact(
name = "Alice",
iconColor = "TestColor",
entries = arrayOf(entry("addr-1", "0xabc", memo = null)),
)
)
// Act
val blob = cipher.encrypt(book, wallet, updatedAt).rightValue()
@ -94,7 +108,13 @@ internal class AddressBookCipherTest {
@Test
fun `GIVEN same book encrypted twice WHEN compared THEN nonce differs but both decrypt to original`() {
// Arrange
val book = addressBook(contact("Alice", entry("addr-1", "0xabc", memo = null)))
val book = addressBook(
contact(
name = "Alice",
iconColor = "TestColor",
entries = arrayOf(entry("addr-1", "0xabc", memo = null)),
)
)
// Act
val first = cipher.encrypt(book, wallet, updatedAt).rightValue()
@ -222,10 +242,12 @@ internal class AddressBookCipherTest {
private fun addressBook(walletId: UserWalletId): AddressBook =
AddressBook(walletId = walletId, contacts = emptyList())
private fun contact(name: String, vararg entries: AddressEntry): Contact = Contact(
private fun contact(name: String, iconColor: String, vararg entries: AddressEntry): Contact = Contact(
id = ContactId("contact-$name"),
walletId = wallet.walletId,
name = requireNotNull(ContactName(name).getOrNull()),
icon = "",
iconColor = iconColor,
createdAt = "2026-01-01T00:00:00.000Z",
updatedAt = "2026-05-22T09:00:00.000Z",
addressEntries = entries.toList(),

View file

@ -80,6 +80,7 @@ class CreateContactUseCaseTest {
val result = useCase(
userWallet = userWallet,
name = "Alice",
iconColor = "TestColor",
network = network,
addressEntries = addressEntries,
)
@ -102,6 +103,7 @@ class CreateContactUseCaseTest {
val result = useCase(
userWallet = userWallet,
name = "Alice",
iconColor = "TestColor",
network = network,
addressEntries = addressEntries,
)
@ -112,11 +114,16 @@ class CreateContactUseCaseTest {
@Test
fun `duplicate name fails without persisting`() = runTest {
every { repository.getContacts(walletId) } returns flowOf(listOf(contact(name = "Alice")))
every { repository.getContacts(walletId) } returns flowOf(
listOf(
contact(name = "Alice", iconColor = "TestColor")
)
)
val result = useCase(
userWallet = userWallet,
name = "alice",
iconColor = "TestColor",
network = network,
addressEntries = addressEntries,
)
@ -133,6 +140,7 @@ class CreateContactUseCaseTest {
val result = useCase(
userWallet = userWallet,
name = "",
iconColor = "TestColor",
network = network,
addressEntries = addressEntries,
)
@ -142,10 +150,12 @@ class CreateContactUseCaseTest {
coVerify(exactly = 0) { repository.saveContact(any()) }
}
private fun contact(name: String): Contact = Contact(
private fun contact(name: String, iconColor: String): Contact = Contact(
id = ContactId("id-$name"),
walletId = walletId,
name = requireNotNull(ContactName(name).getOrNull()),
icon = "",
iconColor = iconColor,
createdAt = expectedTimestamp,
updatedAt = expectedTimestamp,
addressEntries = listOf(

View file

@ -90,6 +90,8 @@ class GetContactsUseCaseTest {
id = ContactId("id-$name"),
walletId = UserWalletId("011"),
name = requireNotNull(ContactName(name).getOrNull()),
icon = "",
iconColor = "KekColor",
createdAt = "2026-01-01T00:00:00.000Z",
updatedAt = "2026-01-01T00:00:00.000Z",
addressEntries = listOf(

View file

@ -109,6 +109,8 @@ class GetVerifiedContactsUseCaseTest {
id = ContactId("id-$name"),
walletId = walletId,
name = requireNotNull(ContactName(name).getOrNull()),
icon = "",
iconColor = "KekColor",
createdAt = "2026-01-01T00:00:00.000Z",
updatedAt = "2026-01-01T00:00:00.000Z",
addressEntries = entries,

View file

@ -124,6 +124,8 @@ class SignAddressEntriesUseCaseTest {
id = ContactId("contact-1"),
walletId = UserWalletId("011"),
name = requireNotNull(ContactName("Alice").getOrNull()),
icon = "",
iconColor = "KekColor",
createdAt = "2026-01-01T00:00:00.000Z",
updatedAt = "2026-01-01T00:00:00.000Z",
addressEntries = entries.toList(),

View file

@ -69,7 +69,7 @@ class UpdateContactUseCaseTest {
@Test
fun `update preserves id and persists signed changes without checking uniqueness`() = runTest {
val existing = contact(name = "Alice")
val existing = contact(name = "Alice", iconColor = "TestColor")
val saved = slot<Contact>()
coEvery { repository.saveContact(capture(saved)) } returns Unit
@ -77,6 +77,7 @@ class UpdateContactUseCaseTest {
userWallet = userWallet,
contact = existing,
name = "Bob",
iconColor = "TestColor",
addressEntries = updatedEntries,
)
@ -96,8 +97,9 @@ class UpdateContactUseCaseTest {
val result = useCase(
userWallet = userWallet,
contact = contact(name = "Alice"),
contact = contact(name = "Alice", iconColor = "TestColor"),
name = "Bob",
iconColor = "TestColor",
addressEntries = updatedEntries,
)
@ -109,8 +111,9 @@ class UpdateContactUseCaseTest {
fun `invalid name fails without persisting`() = runTest {
val result = useCase(
userWallet = userWallet,
contact = contact(name = "Alice"),
contact = contact(name = "Alice", iconColor = "TestColor"),
name = "",
iconColor = "TestColor",
addressEntries = updatedEntries,
)
@ -119,10 +122,12 @@ class UpdateContactUseCaseTest {
coVerify(exactly = 0) { repository.saveContact(any()) }
}
private fun contact(name: String): Contact = Contact(
private fun contact(name: String, iconColor: String): Contact = Contact(
id = ContactId("id-$name"),
walletId = walletId,
name = requireNotNull(ContactName(name).getOrNull()),
icon = "",
iconColor = iconColor,
createdAt = originalTimestamp,
updatedAt = originalTimestamp,
addressEntries = listOf(

View file

@ -64,6 +64,8 @@ class ValidateContactNameUseCaseTest {
id = ContactId("id-$name"),
walletId = walletId,
name = requireNotNull(ContactName(name).getOrNull()),
icon = "",
iconColor = "KekColor",
createdAt = "2026-01-01T00:00:00.000Z",
updatedAt = "2026-01-01T00:00:00.000Z",
addressEntries = listOf(

View file

@ -152,6 +152,8 @@ class VerifyAddressEntriesUseCaseTest {
id = ContactId("contact-1"),
walletId = UserWalletId("011"),
name = requireNotNull(ContactName("Alice").getOrNull()),
icon = "",
iconColor = "KekColor",
createdAt = "2026-01-01T00:00:00.000Z",
updatedAt = "2026-01-01T00:00:00.000Z",
addressEntries = entries.toList(),