Add send and receive support for group member labels.

This commit is contained in:
jeffrey-signal
2026-01-28 12:43:28 -05:00
committed by Greyson Parrelli
parent ce46c44b5d
commit 0a572153f0
21 changed files with 593 additions and 41 deletions

View File

@@ -1,6 +1,7 @@
package org.whispersystems.signalservice.api.groupsv2;
import org.junit.Test;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.Member;
@@ -9,6 +10,7 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedBannedMemb
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberRole;
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMemberRemoval;
@@ -16,7 +18,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedRequesting
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.internal.util.Util;
import java.util.List;
@@ -38,8 +39,8 @@ import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.reque
import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.withProfileKey;
import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber;
@SuppressWarnings("NewClassNamingConvention")
public final class DecryptedGroupUtil_apply_Test {
/**
* Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this.
* <p>
@@ -50,7 +51,7 @@ public final class DecryptedGroupUtil_apply_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(DecryptedGroupChange.class);
assertEquals("DecryptedGroupUtil and its tests need updating to account for new fields on " + DecryptedGroupChange.class.getName(),
24, maxFieldFound);
26, maxFieldFound);
}
@Test
@@ -956,4 +957,99 @@ public final class DecryptedGroupUtil_apply_Test {
.build(),
newGroup);
}
@Test
public void apply_modify_member_label() throws NotAbleToApplyGroupV2ChangeException {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
DecryptedMember existingMember = member(memberUuid);
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(memberUuid))
.labelEmoji("🎉")
.labelString("Test Label")
.build();
DecryptedGroup actualResult = DecryptedGroupUtil.apply(
new DecryptedGroup.Builder()
.revision(10)
.members(List.of(existingMember))
.build(),
new DecryptedGroupChange.Builder()
.revision(11)
.modifyMemberLabel(List.of(modifyLabelAction))
.build()
);
List<DecryptedMember> expectedMembers = List.of(
existingMember.newBuilder()
.labelEmoji("🎉")
.labelString("Test Label")
.build()
);
DecryptedGroup expectedResult = new DecryptedGroup.Builder()
.revision(11)
.members(expectedMembers)
.build();
assertEquals(expectedResult, actualResult);
}
@Test
public void apply_modify_member_label_clear() throws NotAbleToApplyGroupV2ChangeException {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
DecryptedMember member = member(memberUuid)
.newBuilder()
.labelEmoji("🎉")
.labelString("Test Label")
.build();
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(memberUuid))
.labelEmoji("")
.labelString("")
.build();
DecryptedGroup actualResult = DecryptedGroupUtil.apply(
new DecryptedGroup.Builder()
.revision(10)
.members(List.of(member))
.build(),
new DecryptedGroupChange.Builder()
.revision(11)
.modifyMemberLabel(List.of(modifyLabelAction))
.build());
DecryptedGroup expectedResult = new DecryptedGroup.Builder()
.revision(11)
.members(List.of(member(memberUuid)))
.build();
assertEquals(expectedResult, actualResult);
}
@Test(expected = NotAbleToApplyGroupV2ChangeException.class)
public void apply_modify_member_label_for_non_member() throws NotAbleToApplyGroupV2ChangeException {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
UUID nonMemberUuid = UUID.fromString("d2d2d2d2-0000-4000-8000-000000000002");
DecryptedMember member1 = member(memberUuid);
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(nonMemberUuid))
.labelEmoji("🎉")
.labelString("Test Label")
.build();
DecryptedGroupUtil.apply(
new DecryptedGroup.Builder()
.revision(10)
.members(List.of(member1))
.build(),
new DecryptedGroupChange.Builder()
.revision(11)
.modifyMemberLabel(List.of(modifyLabelAction))
.build());
}
}

View File

@@ -1,15 +1,16 @@
package org.whispersystems.signalservice.api.groupsv2;
import org.junit.Test;
import org.signal.core.util.UuidUtil;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.local.DecryptedApproveMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedBannedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel;
import org.signal.storageservice.storage.protos.groups.local.DecryptedRequestingMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.core.util.UuidUtil;
import java.util.List;
import java.util.UUID;
@@ -27,8 +28,8 @@ import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.promo
import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.randomProfileKey;
import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber;
@SuppressWarnings("NewClassNamingConvention")
public final class DecryptedGroupUtil_empty_Test {
/**
* Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this.
* <p>
@@ -39,7 +40,7 @@ public final class DecryptedGroupUtil_empty_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(DecryptedGroupChange.class);
assertEquals("DecryptedGroupUtil and its tests need updating to account for new fields on " + DecryptedGroupChange.class.getName(),
24, maxFieldFound);
26, maxFieldFound);
}
@Test
@@ -266,4 +267,21 @@ public final class DecryptedGroupUtil_empty_Test {
assertFalse(DecryptedGroupUtil.changeIsEmpty(change));
assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change));
}
@Test
public void not_empty_with_modify_member_label_field_26() {
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(UUID.randomUUID()))
.labelEmoji("🔥")
.labelString("Test")
.build();
DecryptedGroupChange change = new DecryptedGroupChange.Builder()
.modifyMemberLabel(List.of(modifyLabelAction))
.build();
assertFalse(DecryptedGroupUtil.changeIsEmpty(change));
assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(change));
assertFalse(DecryptedGroupUtil.changeIsEmptyExceptForBanChangesAndOptionalProfileKeyChanges(change));
}
}

View File

@@ -1,14 +1,15 @@
package org.whispersystems.signalservice.api.groupsv2;
import org.junit.Test;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.internal.util.Util;
import java.util.List;
@@ -408,4 +409,57 @@ public final class GroupChangeReconstructTest {
assertEquals(new DecryptedGroupChange.Builder().deleteBannedMembers(List.of(bannedMember(uuidOld))).build(), decryptedGroupChange);
}
}
@Test
public void member_label_change() {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
DecryptedMember existingMember = member(memberUuid);
DecryptedMember updatedMember = member(memberUuid)
.newBuilder()
.labelEmoji("🎉")
.labelString("New Label")
.build();
DecryptedGroup from = new DecryptedGroup.Builder()
.members(List.of(existingMember))
.build();
DecryptedGroup to = new DecryptedGroup.Builder()
.members(List.of(updatedMember))
.build();
DecryptedGroupChange change = GroupChangeReconstruct.reconstructGroupChange(from, to);
assertEquals(1, change.modifyMemberLabel.size());
assertEquals(UuidUtil.toByteString(memberUuid), change.modifyMemberLabel.get(0).aciBytes);
assertEquals("🎉", change.modifyMemberLabel.get(0).labelEmoji);
assertEquals("New Label", change.modifyMemberLabel.get(0).labelString);
}
@Test
public void member_label_clear() {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
DecryptedMember memberWithLabel = member(memberUuid)
.newBuilder()
.labelEmoji("🎉")
.labelString("existing label")
.build();
DecryptedGroup from = new DecryptedGroup.Builder()
.members(List.of(memberWithLabel))
.build();
DecryptedGroup to = new DecryptedGroup.Builder()
.members(List.of(member(memberUuid)))
.build();
DecryptedGroupChange change = GroupChangeReconstruct.reconstructGroupChange(from, to);
assertEquals(1, change.modifyMemberLabel.size());
assertEquals(UuidUtil.toByteString(memberUuid), change.modifyMemberLabel.get(0).aciBytes);
assertEquals("", change.modifyMemberLabel.get(0).labelEmoji);
assertEquals("", change.modifyMemberLabel.get(0).labelString);
}
}

View File

@@ -10,8 +10,8 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber;
@SuppressWarnings("NewClassNamingConvention")
public final class GroupChangeUtil_changeIsEmpty_Test {
/**
* Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this.
* <p>
@@ -22,7 +22,7 @@ public final class GroupChangeUtil_changeIsEmpty_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(GroupChange.Actions.class);
assertEquals("GroupChangeUtil and its tests need updating to account for new fields on " + GroupChange.Actions.class.getName(),
25, maxFieldFound);
26, maxFieldFound);
}
@Test
@@ -227,4 +227,13 @@ public final class GroupChangeUtil_changeIsEmpty_Test {
assertFalse(GroupChangeUtil.changeIsEmpty(actions));
}
@Test
public void not_empty_with_modify_member_label_field_26() {
GroupChange.Actions actions = new GroupChange.Actions.Builder()
.modifyMemberLabel(List.of(new GroupChange.Actions.ModifyMemberLabelAction()))
.build();
assertFalse(GroupChangeUtil.changeIsEmpty(actions));
}
}

View File

@@ -1,19 +1,20 @@
package org.whispersystems.signalservice.api.groupsv2;
import org.junit.Test;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.MemberBanned;
import org.signal.storageservice.storage.protos.groups.GroupChange;
import org.signal.storageservice.storage.protos.groups.Member;
import org.signal.storageservice.storage.protos.groups.MemberBanned;
import org.signal.storageservice.storage.protos.groups.MemberPendingProfileKey;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel;
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.internal.util.Util;
import java.util.List;
@@ -40,8 +41,8 @@ import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.rando
import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.requestingMember;
import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber;
@SuppressWarnings("NewClassNamingConvention")
public final class GroupChangeUtil_resolveConflict_Test {
/**
* Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this.
* <p>
@@ -52,7 +53,7 @@ public final class GroupChangeUtil_resolveConflict_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(DecryptedGroupChange.class);
assertEquals("GroupChangeUtil#resolveConflict and its tests need updating to account for new fields on " + DecryptedGroupChange.class.getName(),
24, maxFieldFound);
26, maxFieldFound);
}
/**
@@ -65,7 +66,7 @@ public final class GroupChangeUtil_resolveConflict_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(DecryptedGroupChange.class);
assertEquals("GroupChangeUtil#resolveConflict and its tests need updating to account for new fields on " + GroupChange.class.getName(),
24, maxFieldFound);
26, maxFieldFound);
}
/**
@@ -854,4 +855,57 @@ public final class GroupChangeUtil_resolveConflict_Test {
.build();
assertEquals(expected, resolvedActions);
}
@Test
public void field_26__modify_member_label__remove_if_label_already_matches() {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
DecryptedMember existingMember = member(memberUuid)
.newBuilder()
.labelEmoji("🔥")
.labelString("matching label")
.build();
DecryptedGroup existingGroup = new DecryptedGroup.Builder()
.revision(10)
.members(List.of(existingMember))
.build();
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(memberUuid))
.labelEmoji("🔥")
.labelString("matching label")
.build();
DecryptedGroupChange conflictingChange = new DecryptedGroupChange.Builder()
.modifyMemberLabel(List.of(modifyLabelAction))
.build();
DecryptedGroupChange.Builder resolvedActions = GroupChangeUtil.resolveConflict(existingGroup, conflictingChange);
assertTrue(resolvedActions.build().modifyMemberLabel.isEmpty());
}
@Test
public void field_26__modify_member_label__remove_if_member_not_in_group() {
UUID memberUuuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
UUID nonMemberUuid = UUID.fromString("d2d2d2d2-0000-4000-8000-000000000002");
DecryptedGroup existingGroup = new DecryptedGroup.Builder()
.revision(10)
.members(List.of(member(memberUuuid)))
.build();
DecryptedModifyMemberLabel modifyLabelAction = new org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(nonMemberUuid))
.labelEmoji("🔥")
.labelString("foo bar")
.build();
DecryptedGroupChange conflictingChange = new DecryptedGroupChange.Builder()
.modifyMemberLabel(List.of(modifyLabelAction))
.build();
DecryptedGroupChange.Builder resolved = GroupChangeUtil.resolveConflict(existingGroup, conflictingChange);
assertTrue(resolved.build().modifyMemberLabel.isEmpty());
}
}

View File

@@ -1,15 +1,16 @@
package org.whispersystems.signalservice.api.groupsv2;
import org.junit.Test;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.storageservice.storage.protos.groups.AccessControl;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroup;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel;
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.internal.util.Util;
import java.util.List;
@@ -32,8 +33,8 @@ import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.rando
import static org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.requestingMember;
import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber;
@SuppressWarnings("NewClassNamingConvention")
public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test {
/**
* Reflects over the generated protobuf class and ensures that no new fields have been added since we wrote this.
* <p>
@@ -44,7 +45,7 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(DecryptedGroupChange.class);
assertEquals("GroupChangeUtil#resolveConflict and its tests need updating to account for new fields on " + DecryptedGroupChange.class.getName(),
24, maxFieldFound);
26, maxFieldFound);
}
/**
@@ -673,4 +674,57 @@ public final class GroupChangeUtil_resolveConflict_decryptedOnly_Test {
assertEquals(expected, resolvedChanges);
}
@Test
public void field_26__modify_member_label__remove_if_label_already_matches() {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
DecryptedMember existingMember = member(memberUuid)
.newBuilder()
.labelEmoji("🔥")
.labelString("Already Set")
.build();
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(memberUuid))
.labelEmoji("🔥")
.labelString("Already Set")
.build();
DecryptedGroup existingGroup = new DecryptedGroup.Builder()
.revision(10)
.members(List.of(existingMember))
.build();
DecryptedGroupChange conflictingChange = new DecryptedGroupChange.Builder()
.modifyMemberLabel(List.of(modifyLabelAction))
.build();
DecryptedGroupChange.Builder resolved = GroupChangeUtil.resolveConflict(existingGroup, conflictingChange);
assertTrue(resolved.build().modifyMemberLabel.isEmpty());
}
@Test
public void field_26__modify_member_label__remove_if_member_not_in_group() {
UUID memberUuid = UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001");
UUID notInGroupUuid = UUID.fromString("d2d2d2d2-0000-4000-8000-000000000002");
DecryptedGroup existingGroup = new DecryptedGroup.Builder()
.revision(10)
.members(List.of(member(memberUuid)))
.build();
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(UuidUtil.toByteString(notInGroupUuid))
.labelEmoji("🔥")
.labelString("Test")
.build();
DecryptedGroupChange conflictingChange = new DecryptedGroupChange.Builder()
.modifyMemberLabel(List.of(modifyLabelAction))
.build();
DecryptedGroupChange.Builder resolved = GroupChangeUtil.resolveConflict(existingGroup, conflictingChange);
assertTrue(resolved.build().modifyMemberLabel.isEmpty());
}
}

View File

@@ -2,6 +2,9 @@ package org.whispersystems.signalservice.api.groupsv2;
import org.junit.Before;
import org.junit.Test;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.UuidUtil;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.groups.ClientZkGroupCipher;
@@ -23,6 +26,7 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedApproveMem
import org.signal.storageservice.storage.protos.groups.local.DecryptedBannedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedGroupChange;
import org.signal.storageservice.storage.protos.groups.local.DecryptedMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberLabel;
import org.signal.storageservice.storage.protos.groups.local.DecryptedModifyMemberRole;
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMember;
import org.signal.storageservice.storage.protos.groups.local.DecryptedPendingMemberRemoval;
@@ -30,9 +34,6 @@ import org.signal.storageservice.storage.protos.groups.local.DecryptedRequesting
import org.signal.storageservice.storage.protos.groups.local.DecryptedString;
import org.signal.storageservice.storage.protos.groups.local.DecryptedTimer;
import org.signal.storageservice.storage.protos.groups.local.EnabledState;
import org.signal.core.models.ServiceId.ACI;
import org.signal.core.models.ServiceId.PNI;
import org.signal.core.util.UuidUtil;
import org.whispersystems.signalservice.internal.util.Util;
import org.whispersystems.signalservice.testutil.LibSignalLibraryUtil;
@@ -50,8 +51,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.whispersystems.signalservice.api.groupsv2.ProtobufTestUtils.getMaxDeclaredFieldNumber;
@SuppressWarnings("NewClassNamingConvention")
public final class GroupsV2Operations_decrypt_change_Test {
private GroupSecretParams groupSecretParams;
private GroupsV2Operations.GroupOperations groupOperations;
private ClientZkOperations clientZkOperations;
@@ -72,7 +73,7 @@ public final class GroupsV2Operations_decrypt_change_Test {
int maxFieldFound = getMaxDeclaredFieldNumber(DecryptedGroupChange.class);
assertEquals("GroupV2Operations#decryptChange and its tests need updating to account for new fields on " + DecryptedGroupChange.class.getName(),
24,
26,
maxFieldFound);
}
@@ -459,6 +460,22 @@ public final class GroupsV2Operations_decrypt_change_Test {
.build())));
}
@Test
public void can_decrypt_modify_member_label_field26() {
ACI aci = ACI.from(UUID.fromString("d1d1d1d1-0000-4000-8000-000000000001"));
DecryptedModifyMemberLabel modifyLabelAction = new DecryptedModifyMemberLabel.Builder()
.aciBytes(aci.toByteString())
.labelString("Label Text")
.labelEmoji("🔥")
.build();
assertDecryption(
groupOperations.createChangeMemberLabel(aci, "Label Text", "🔥"),
new DecryptedGroupChange.Builder().modifyMemberLabel(List.of(modifyLabelAction))
);
}
private static ProfileKey newProfileKey() {
try {
return new ProfileKey(Util.getSecretBytes(32));