TM-SGNL-iOS/SignalServiceKit/tests/Groups/GroupModelsTest.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

231 lines
17 KiB
Swift

//
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import LibSignalClient
import XCTest
@testable import SignalServiceKit
private extension Aci {
static let aci1 = Aci.randomForTesting()
static let aci2 = Aci.randomForTesting()
static let aci3 = Aci.randomForTesting()
}
class GroupModelsTest: SSKBaseTest {
func testGroupMembershipChangingFullMembers() {
var builder1 = GroupMembership.Builder()
builder1.addFullMember(.aci1, role: .normal)
let membership1 = builder1.build()
var builder2 = GroupMembership.Builder()
builder2.addFullMember(.aci1, role: .administrator)
let membership2 = builder2.build()
var builder3 = GroupMembership.Builder()
builder3.addFullMember(.aci1, role: .normal)
builder3.addFullMember(.aci2, role: .normal)
let membership3 = builder3.build()
var builder4 = GroupMembership.Builder()
builder4.addFullMember(.aci1, role: .normal)
let membership4 = builder4.build()
XCTAssertEqual(membership1, membership4)
XCTAssertNotEqual(membership1, membership2)
XCTAssertNotEqual(membership1, membership3)
XCTAssertNotEqual(membership2, membership3)
}
func testGroupMembershipChangingDidJoinFromInviteLink() {
var builder1 = GroupMembership.Builder()
builder1.addFullMember(.aci1, role: .normal, didJoinFromInviteLink: true)
let membership1 = builder1.build()
var builder2 = GroupMembership.Builder()
builder2.addFullMember(.aci1, role: .normal, didJoinFromInviteLink: false)
let membership2 = builder2.build()
XCTAssertEqual(membership1, membership2)
}
func testGroupMembershipChangingRequestingMembers() {
var builder1 = GroupMembership.Builder()
builder1.addFullMember(.aci1, role: .normal)
let membership1 = builder1.build()
var builder2 = GroupMembership.Builder()
builder2.addFullMember(.aci1, role: .normal)
builder2.addRequestingMember(Aci.aci2)
let membership2 = builder2.build()
var builder3 = GroupMembership.Builder()
builder3.addFullMember(.aci1, role: .normal)
builder3.addRequestingMember(Aci.aci3)
let membership3 = builder3.build()
var builder4 = GroupMembership.Builder()
builder4.addFullMember(.aci1, role: .normal)
builder4.addRequestingMember(Aci.aci2)
let membership4 = builder4.build()
XCTAssertFalse(membership1 == membership2)
XCTAssertFalse(membership1 == membership3)
XCTAssertFalse(membership2 == membership3)
XCTAssertTrue(membership2 == membership4)
}
func testGroupMembershipChangingBannedMembers() {
var builder1 = GroupMembership.Builder()
builder1.addFullMember(.aci1, role: .normal)
let membership1 = builder1.build()
var builder2 = membership1.asBuilder
builder2.addFullMember(.aci1, role: .normal)
builder2.addBannedMember(.aci2, bannedAtTimestamp: 3)
let membership2 = builder2.build()
var builder3 = GroupMembership.Builder()
builder3.addFullMember(.aci1, role: .normal)
builder3.addBannedMember(.aci2, bannedAtTimestamp: 12)
let membership3 = builder3.build()
var builder4 = GroupMembership.Builder()
builder4.addFullMember(.aci1, role: .normal)
builder4.addBannedMember(.aci2, bannedAtTimestamp: 3)
builder4.addBannedMember(.aci3, bannedAtTimestamp: 4)
let membership4 = builder4.build()
var builder5 = GroupMembership.Builder()
builder5.addFullMember(.aci1, role: .normal)
builder5.addBannedMember(.aci2, bannedAtTimestamp: 3)
builder5.addBannedMember(.aci3, bannedAtTimestamp: 4)
let membership5 = builder5.build()
XCTAssertNotEqual(membership1, membership2)
XCTAssertNotEqual(membership2, membership3)
XCTAssertNotEqual(membership3, membership4)
XCTAssertEqual(membership4, membership5)
}
func testTSGroupModelBackwardsCompatibleDeserialization() throws {
let groupIdLength = 16 // Taken from kGroupIdLength at the time of archiving.
let expectedGroupId = Data(repeating: 8, count: groupIdLength)
// hexstring generated by archiving:
// let model = TSGroupModel(
// groupId: expectedGroupId,
// name: "name",
// avatarData: nil,
// members: [],
// addedBy: nil
// )
// try NSKeyedArchiver.archivedData(withRootObject: model, requiringSecureCoding: false).hexadecimalString
let hexData = "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001a90b0c191a1b1c1d212755246e756c6cd60d0e0f1011121314151617185767726f757049645624636c6173735967726f75704e616d655c67726f75704d656d626572735f100f4d544c4d6f64656c56657273696f6e5f101767726f75704d6f64656c536368656d6156657273696f6e80058008800480068002800310001002546e616d654f101008080808080808080808080808080808d21e0e1f205a4e532e6f626a65637473a08007d2222324255a24636c6173736e616d655824636c6173736573574e534172726179a22426584e534f626a656374d2222328295c545347726f75704d6f64656ca32a2b265c545347726f75704d6f64656c584d544c4d6f64656c00080011001a00240029003200370049004c00510053005d006300700078007f0089009600a800c200c400c600c800ca00cc00ce00d000d200d700ea00ef00fa00fb00fd0102010d0116011e0121012a012f013c0140014d0000000000000201000000000000002c00000000000000000000000000000156"
let encodedData = Data.data(fromHex: hexData)!
let groupModel = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(ofClass: TSGroupModel.self, from: encodedData, requiringSecureCoding: false))
XCTAssertEqual(groupModel.groupId, expectedGroupId)
}
func testTSGroupModelV2BackwardsCompatibleDeserialization() throws {
/// The value of ``kGroupIdLengthV2`` at the time of serialization.
let groupIdLength = 32
/// Generates a hex string of a serialized ``TSGroupModel`` with the
/// given parameters, and the rest hardcoded.
///
/// Use this to generate new models for back-compat deserialization
/// testing as necessary.
func generateHexString(
groupIdRepeats: UInt8,
isJoinRequestPlaceholder: Bool
) -> String {
let model = TSGroupModelV2(
groupId: Data(repeating: groupIdRepeats, count: groupIdLength),
name: "name",
descriptionText: "description",
avatarData: nil,
groupMembership: .empty,
groupAccess: .allAccess,
revision: 1,
secretParamsData: Data(repeating: 8, count: 10),
avatarUrlPath: nil,
inviteLinkPassword: nil,
isAnnouncementsOnly: false,
isJoinRequestPlaceholder: isJoinRequestPlaceholder,
wasJustMigrated: false,
didJustAddSelfViaGroupLink: false,
addedByAddress: nil,
droppedMembers: []
)
return try! NSKeyedArchiver.archivedData(
withRootObject: model,
requiringSecureCoding: false
).hexadecimalString
}
let testCases: [(encodedData: Data, expectedGroupId: Data, isJoinRequestPlaceholder: Bool)] = [
(
encodedData: .data(
fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001af10140b0c2d2e2f30313a3b3c44454d4e54585c5f626355246e756c6cdf10100d0e0f101112131415161718191a1b1c1d1e1f20211d2324251d2728292a1d1d5f10197761734a7573744372656174656442794c6f63616c557365725f1010736563726574506172616d73446174615f100f4d544c4d6f64656c56657273696f6e566163636573735f100f6465736372697074696f6e546578745f10126973506c616365686f6c6465724d6f64656c587265766973696f6e5a6d656d626572736869705624636c6173735f101a6469644a75737441646453656c6656696147726f75704c696e6b5e64726f707065644d656d626572735f101767726f75704d6f64656c536368656d6156657273696f6e5967726f75704e616d655767726f757049645f10136973416e6e6f756e63656d656e74734f6e6c795f100f7761734a7573744d696772617465648005800380028006800a80058008800b8013800580108007801280048005800510004a080808080808080808084f1020080808080808080808080808080808080808080808080808080808080808080808d515320f333435231f28285f101161646446726f6d496e766974654c696e6b576d656d626572735a617474726962757465738009800880028007800710021001d23d3e3f405a24636c6173736e616d655824636c61737365735f101c5369676e616c536572766963654b69742e47726f7570416363657373a34142435f101c5369676e616c536572766963654b69742e47726f7570416363657373584d544c4d6f64656c584e534f626a6563745b6465736372697074696f6ed415464748494a4a4c5f1010696e76616c6964496e766974654d61705d62616e6e65644d656d626572735c6d656d626572537461746573800f800d800d800c425b5dd34f5015515253574e532e6b6579735a4e532e6f626a65637473a0a0800ed23d3e55565c4e5344696374696f6e617279a257435c4e5344696374696f6e617279d23d3e595a5f10205369676e616c536572766963654b69742e47726f75704d656d62657273686970a35b42435f10205369676e616c536572766963654b69742e47726f75704d656d62657273686970d250155d5ea08011d23d3e6061574e534172726179a26043546e616d65d23d3e64655f101f5369676e616c536572766963654b69742e545347726f75704d6f64656c5632a4666742435f101f5369676e616c536572766963654b69742e545347726f75704d6f64656c56325c545347726f75704d6f64656c00080011001a00240029003200370049004c00510053006a0070009300af00c200d400db00ed0102010b0116011d013a01490163016d0175018b019d019f01a101a301a501a701a901ab01ad01af01b101b301b501b701b901bb01bd01bf01ca01ed01ee01f9020d021502200222022402260228022a022c022e0233023e02470266026a02890292029b02a702b002c302d102de02e002e202e402e602e902f002f80303030403050307030c0319031c0329032e035103550378037d037e03800385038d03900395039a03bc03c103e300000000000002010000000000000068000000000000000000000000000003f0"
)!,
expectedGroupId: Data(repeating: 8, count: groupIdLength),
isJoinRequestPlaceholder: false
),
(
encodedData: .data(
fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001af10140b0c2b2c2d2e37383941424a4b5155595c5f606155246e756c6cdf100f0d0e0f101112131415161718191a1b1c1d1e1f20212223202526272820205f1010736563726574506172616d73446174615f100f4d544c4d6f64656c56657273696f6e566163636573735f100f6465736372697074696f6e546578745f10126973506c616365686f6c6465724d6f64656c587265766973696f6e5a6d656d626572736869705624636c6173735f101a6469644a75737441646453656c6656696147726f75704c696e6b5e64726f707065644d656d626572735f101767726f75704d6f64656c536368656d6156657273696f6e5967726f75704e616d655767726f757049645f10136973416e6e6f756e63656d656e74734f6e6c795f100f7761734a7573744d69677261746564800380028005800980048007800a80138004800f8006801180128004800410004a0808080808080808080808d5142f0e303132211d26265f101161646446726f6d496e766974654c696e6b576d656d626572735a617474726962757465738008800780028006800610021001d23a3b3c3d5a24636c6173736e616d655824636c61737365735f101c5369676e616c536572766963654b69742e47726f7570416363657373a33e3f405f101c5369676e616c536572766963654b69742e47726f7570416363657373584d544c4d6f64656c584e534f626a6563745b6465736372697074696f6ed414434445464747495f1010696e76616c6964496e766974654d61705d62616e6e65644d656d626572735c6d656d626572537461746573800e800c800c800b425b5dd34c4d144e4f50574e532e6b6579735a4e532e6f626a65637473a0a0800dd23a3b52535c4e5344696374696f6e617279a254405c4e5344696374696f6e617279d23a3b56575f10205369676e616c536572766963654b69742e47726f75704d656d62657273686970a3583f405f10205369676e616c536572766963654b69742e47726f75704d656d62657273686970d24d145a5ba08010d23a3b5d5e574e534172726179a25d40546e616d654f10200808080808080808080808080808080808080808080808080808080808080808d23a3b62635f101f5369676e616c536572766963654b69742e545347726f75704d6f64656c5632a464653f405f101f5369676e616c536572766963654b69742e545347726f75704d6f64656c56325c545347726f75704d6f64656c00080011001a00240029003200370049004c00510053006a0070009100a400b600bd00cf00e400ed00f800ff011c012b0145014f0157016d017f01810183018501870189018b018d018f01910193019501970199019b019d019f01aa01ab01b601ca01d201dd01df01e101e301e501e701e901eb01f001fb0204022302270246024f02580264026d0280028e029b029d029f02a102a302a602ad02b502c002c102c202c402c902d602d902e602eb030e03120335033a033b033d0342034a034d03520375037a039c03a103c300000000000002010000000000000066000000000000000000000000000003d0"
)!,
expectedGroupId: Data(repeating: 8, count: groupIdLength),
isJoinRequestPlaceholder: false
),
(
encodedData: .data(
fromHex: "62706c6973743030d4010203040506070a582476657273696f6e592461726368697665725424746f7058246f626a6563747312000186a05f100f4e534b657965644172636869766572d1080954726f6f748001af10150b0c2b2c2d2e3738394142434b4c52565a5d60616255246e756c6cdf100f0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272824245f1010736563726574506172616d73446174615f100f4d544c4d6f64656c56657273696f6e566163636573735f100f6465736372697074696f6e546578745f10126973506c616365686f6c6465724d6f64656c587265766973696f6e5a6d656d626572736869705624636c6173735f101a6469644a75737441646453656c6656696147726f75704c696e6b5e64726f707065644d656d626572735f101767726f75704d6f64656c536368656d6156657273696f6e5967726f75704e616d655767726f757049645f10136973416e6e6f756e63656d656e74734f6e6c795f100f7761734a7573744d696772617465648003800280058009800a8007800b8014800480108006801280138004800410004a0808080808080808080808d5142f0e303132211d26265f101161646446726f6d496e766974654c696e6b576d656d626572735a617474726962757465738008800780028006800610021001d23a3b3c3d5a24636c6173736e616d655824636c61737365735f101c5369676e616c536572766963654b69742e47726f7570416363657373a33e3f405f101c5369676e616c536572766963654b69742e47726f7570416363657373584d544c4d6f64656c584e534f626a6563745b6465736372697074696f6e09d4144445464748484a5f1010696e76616c6964496e766974654d61705d62616e6e65644d656d626572735c6d656d626572537461746573800f800d800d800c425b5dd34d4e144f5051574e532e6b6579735a4e532e6f626a65637473a0a0800ed23a3b53545c4e5344696374696f6e617279a255405c4e5344696374696f6e617279d23a3b57585f10205369676e616c536572766963654b69742e47726f75704d656d62657273686970a3593f405f10205369676e616c536572766963654b69742e47726f75704d656d62657273686970d24e145b5ca08011d23a3b5e5f574e534172726179a25e40546e616d654f10200707070707070707070707070707070707070707070707070707070707070707d23a3b63645f101f5369676e616c536572766963654b69742e545347726f75704d6f64656c5632a465663f405f101f5369676e616c536572766963654b69742e545347726f75704d6f64656c56325c545347726f75704d6f64656c00080011001a00240029003200370049004c00510053006b0071009200a500b700be00d000e500ee00f90100011d012c014601500158016e01800182018401860188018a018c018e01900192019401960198019a019c019e01a001ab01ac01b701cb01d301de01e001e201e401e601e801ea01ec01f101fc02050224022802470250025902650266026f02820290029d029f02a102a302a502a802af02b702c202c302c402c602cb02d802db02e802ed031003140337033c033d033f0344034c034f03540377037c039e03a303c500000000000002010000000000000067000000000000000000000000000003d2"
)!,
expectedGroupId: Data(repeating: 7, count: groupIdLength),
isJoinRequestPlaceholder: true
)
]
for (encodedData, expectedGroupId, isJoinRequestPlaceholder) in testCases {
let groupModel = try XCTUnwrap(NSKeyedUnarchiver.unarchivedObject(
ofClass: TSGroupModelV2.self,
from: encodedData,
requiringSecureCoding: false
))
XCTAssertEqual(groupModel.groupId, expectedGroupId)
XCTAssertEqual(groupModel.groupName, "name")
XCTAssertEqual(groupModel.descriptionText, "description")
XCTAssertNil(groupModel.avatarData)
XCTAssertEqual(groupModel.groupMembership, .empty)
XCTAssertEqual(groupModel.access, .allAccess)
XCTAssertEqual(groupModel.revision, 1)
XCTAssertEqual(groupModel.secretParamsData, Data(repeating: 8, count: 10))
XCTAssertNil(groupModel.avatarUrlPath)
XCTAssertNil(groupModel.inviteLinkPassword)
XCTAssertFalse(groupModel.isAnnouncementsOnly)
XCTAssertEqual(groupModel.isJoinRequestPlaceholder, isJoinRequestPlaceholder)
XCTAssertFalse(groupModel.wasJustMigrated)
XCTAssertFalse(groupModel.didJustAddSelfViaGroupLink)
XCTAssertNil(groupModel.addedByAddress)
XCTAssertEqual(groupModel.droppedMembers, [])
}
}
}