Display member label on recipient details sheet.

This commit is contained in:
jeffrey-signal
2026-02-06 12:18:15 -05:00
committed by Greyson Parrelli
parent fae4ca91bd
commit d5b2f4fdd3
10 changed files with 352 additions and 88 deletions

View File

@@ -15,6 +15,7 @@ import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.testing.CoroutineDispatcherRule
@@ -26,13 +27,14 @@ class MemberLabelViewModelTest {
val dispatcherRule = CoroutineDispatcherRule(testDispatcher)
private val memberLabelRepo = mockk<MemberLabelRepository>(relaxUnitFun = true)
private val groupId = mockk<GroupId.V2>()
private val recipientId = RecipientId.from(1L)
@Test
fun `isSaveEnabled returns true when label text is different from the original value`() {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("Modified")
assertTrue(viewModel.uiState.value.isSaveEnabled)
@@ -40,9 +42,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns false when label text is the same as the original value`() {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("Original")
assertFalse(viewModel.uiState.value.isSaveEnabled)
@@ -50,9 +52,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns true when label text is valid and the emoji is different from the original value`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelEmojiChanged("🎉")
assertTrue(viewModel.uiState.value.isSaveEnabled)
@@ -60,18 +62,18 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns false when the label and emoji are not changed`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Label")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Label")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
assertFalse(viewModel.uiState.value.isSaveEnabled)
}
@Test
fun `isSaveEnabled returns false when the label and emoji are changed to the original value`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelEmojiChanged("🫢")
viewModel.onLabelTextChanged("Modified")
@@ -84,9 +86,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns false when label is too short`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("")
viewModel.onLabelEmojiChanged("🎉")
@@ -95,9 +97,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns true when clearLabel is called with existing label and emoji`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.clearLabel()
assertTrue(viewModel.uiState.value.isSaveEnabled)
@@ -105,9 +107,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns true when clearLabel is called with existing label without emoji`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.clearLabel()
assertTrue(viewModel.uiState.value.isSaveEnabled)
@@ -115,9 +117,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns false when clearLabel is called with no existing label`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns null
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns null
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.clearLabel()
assertFalse(viewModel.uiState.value.isSaveEnabled)
@@ -125,9 +127,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns true when both emoji and label are modified`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("New Label")
viewModel.onLabelEmojiChanged("🚀")
@@ -136,9 +138,9 @@ class MemberLabelViewModelTest {
@Test
fun `isSaveEnabled returns false when only emoji is changed without an existing label`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns null
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns null
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelEmojiChanged("🎉")
assertFalse(viewModel.uiState.value.isSaveEnabled)
@@ -146,76 +148,77 @@ class MemberLabelViewModelTest {
@Test
fun `save does not call setLabel when isSaveEnabled is false`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.save()
coVerify(exactly = 0) { memberLabelRepo.setLabel(any()) }
coVerify(exactly = 0) { memberLabelRepo.setLabel(groupId, any()) }
}
@Test
fun `save does not call setLabel when label is less than 1 character`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Label")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("")
viewModel.onLabelEmojiChanged("🎉")
viewModel.save()
coVerify(exactly = 0) { memberLabelRepo.setLabel(any()) }
coVerify(exactly = 0) { memberLabelRepo.setLabel(groupId, any()) }
}
@Test
fun `save calls setLabel with truncated label when label exceeds max length`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns null
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns null
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("A".repeat(30))
viewModel.save()
coVerify(exactly = 1) {
memberLabelRepo.setLabel(
match { it.text.length == 24 }
groupId = groupId,
label = match { it.text.length == 24 }
)
}
}
@Test
fun `save does not call setLabel when emoji is set with no label`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns null
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns null
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelEmojiChanged("🎉")
viewModel.save()
coVerify(exactly = 0) { memberLabelRepo.setLabel(any()) }
coVerify(exactly = 0) { memberLabelRepo.setLabel(groupId, any()) }
}
@Test
fun `save calls setLabel when label change is valid`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = null, text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.onLabelTextChanged("New Label")
viewModel.onLabelEmojiChanged("🎉")
viewModel.save()
coVerify(exactly = 1) {
memberLabelRepo.setLabel(MemberLabel(text = "New Label", emoji = "🎉"))
memberLabelRepo.setLabel(groupId, MemberLabel(text = "New Label", emoji = "🎉"))
}
}
@Test
fun `save calls setLabel with cleared values when clearLabel is called`() = runTest(testDispatcher) {
coEvery { memberLabelRepo.getLabel(any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
coEvery { memberLabelRepo.getLabel(groupId, any<RecipientId>()) } returns MemberLabel(emoji = "🎉", text = "Original")
val viewModel = MemberLabelViewModel(memberLabelRepo, recipientId)
val viewModel = MemberLabelViewModel(memberLabelRepo, groupId, recipientId)
viewModel.clearLabel()
viewModel.save()
coVerify(exactly = 1) {
memberLabelRepo.setLabel(MemberLabel(text = "", emoji = null))
memberLabelRepo.setLabel(groupId, MemberLabel(text = "", emoji = null))
}
}
}