TM-SGNL-iOS/SignalServiceKit/tests/Messages/Interactions/TSInfoMessage+LegacyPersistablegroupUpdateItemTest.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

169 lines
6.3 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import LibSignalClient
import XCTest
@testable import SignalServiceKit
class TSInfoMessageLegacyPersistableGroupUpdateItemTest: XCTestCase {
private typealias UpdateItem = TSInfoMessage.LegacyPersistableGroupUpdateItem
// MARK: - Hardcoded constant data
enum HardcodedDataTestMode {
case runTest
case printStrings
/// Toggle this to use ``testHardcodedJsonDataDecodes()`` to print
/// hardcoded strings, for example when adding new constants.
static let mode: Self = .runTest
}
func testHardcodedJsonDataDecodes() {
switch HardcodedDataTestMode.mode {
case .printStrings:
UpdateItem.printHardcodedJsonDataForConstants()
case .runTest:
for (idx, (constant, jsonData)) in UpdateItem.constants.enumerated() {
do {
let decoded = try JSONDecoder().decode(UpdateItem.self, from: jsonData)
try constant.validate(against: decoded)
} catch let error where error is DecodingError {
XCTFail("Failed to decode JSON model for constant \(idx): \(error)")
} catch ValidatableModelError.failedToValidate {
XCTFail("Failed to validate JSON-decoded model for constant \(idx)")
} catch {
XCTFail("Unexpected error for constant \(idx)")
}
}
}
}
func testConvertToNewUpdateItem() throws {
let updaterAci = Aci.randomForTesting()
for (constant, _) in UpdateItem.constants {
let expectedNewValue: TSInfoMessage.PersistableGroupUpdateItem
switch constant {
case let .sequenceOfInviteLinkRequestAndCancels(count, isTail):
expectedNewValue = .sequenceOfInviteLinkRequestAndCancels(
requester: updaterAci.codableUuid,
count: count,
isTail: isTail
)
case let .inviteRemoved(_, wasLocalUser):
if wasLocalUser {
expectedNewValue = .localUserInviteRevoked(
revokerAci: updaterAci.codableUuid
)
} else {
expectedNewValue = .unnamedUserInvitesWereRevokedByOtherUser(
updaterAci: updaterAci.codableUuid,
count: 1
)
}
case let .invitedPniPromotedToFullMemberAci(_, aci):
expectedNewValue = .invitedPniPromotedToFullMemberAci(
newMember: aci,
inviter: nil
)
}
guard let newValue = constant.toNewItem(
updater: .aci(updaterAci),
oldGroupModel: nil,
localIdentifiers: .init(
aci: .randomForTesting(),
pni: Pni.constantForTesting("PNI:7CE80DE3-6243-4AD5-AE60-0D1F205391DA"),
e164: .init("+15555555555")!
)
) else {
XCTFail("Should always be able to convert!")
return
}
try newValue.validate(against: expectedNewValue)
}
}
}
extension TSInfoMessage.LegacyPersistableGroupUpdateItem: ValidatableModel {
static var constants: [(TSInfoMessage.LegacyPersistableGroupUpdateItem, jsonData: Data)] {
[
(
.sequenceOfInviteLinkRequestAndCancels(count: 12, isTail: true),
Data(#"{"sequenceOfInviteLinkRequestAndCancels":{"count":12,"isTail":true}}"#.utf8)
),
(
.sequenceOfInviteLinkRequestAndCancels(count: 0, isTail: false),
Data(#"{"sequenceOfInviteLinkRequestAndCancels":{"count":0,"isTail":false}}"#.utf8)
),
(
.invitedPniPromotedToFullMemberAci(
pni: Pni.constantForTesting("PNI:7CE80DE3-6243-4AD5-AE60-0D1F205391DA").codableUuid,
aci: Aci.constantForTesting("56EE0EF4-A7DF-4B52-BFAF-C637F15B4FEC").codableUuid
),
Data(#"{"invitedPniPromotedToFullMemberAci":{"pni":"7CE80DE3-6243-4AD5-AE60-0D1F205391DA","aci":"56EE0EF4-A7DF-4B52-BFAF-C637F15B4FEC"}}"#.utf8)
),
(
.inviteRemoved(
invitee: Aci.constantForTesting("56EE0EF4-A7DF-4B52-BFAF-C637F15B4FEC").codableUppercaseString,
wasLocalUser: false
),
Data(#"{"inviteRemoved":{"invitee":"56EE0EF4-A7DF-4B52-BFAF-C637F15B4FEC","wasLocalUser":false}}"#.utf8)
),
(
.inviteRemoved(
invitee: Pni.constantForTesting("PNI:7CE80DE3-6243-4AD5-AE60-0D1F205391DA").codableUppercaseString,
wasLocalUser: true
),
Data(#"{"inviteRemoved":{"wasLocalUser":true,"invitee":"PNI:7CE80DE3-6243-4AD5-AE60-0D1F205391DA"}}"#.utf8)
),
]
}
func validate(against: TSInfoMessage.LegacyPersistableGroupUpdateItem) throws {
var validated: Bool = false
switch (self, against) {
case let (
.sequenceOfInviteLinkRequestAndCancels(selfCount, selfIsTail),
.sequenceOfInviteLinkRequestAndCancels(againstCount, againstIsTail)
):
if
selfCount == againstCount,
selfIsTail == againstIsTail
{
validated = true
}
case let (
.invitedPniPromotedToFullMemberAci(selfPni, selfAci),
.invitedPniPromotedToFullMemberAci(againstPni, againstAci)
):
if
selfPni == againstPni,
selfAci == againstAci
{
validated = true
}
case let (
.inviteRemoved(selfInvitee, selfWasLocalUser),
.inviteRemoved(againstInvitee, againstWasLocalUser)
):
if
selfInvitee == againstInvitee,
selfWasLocalUser == againstWasLocalUser
{
validated = true
}
default:
break
}
guard validated else {
throw ValidatableModelError.failedToValidate
}
}
}