// // Copyright 2024 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // @testable import SignalServiceKit import XCTest class MessageStickerSerializationTest: XCTestCase { // MARK: - Hardcoded constant data enum HardcodedDataTestMode { case runTest case printStrings /// Toggle this to use ``testHardcodedArchiverDataDecodes()`` to print /// hardcoded strings, for example when adding new constants. static let mode: Self = .runTest } func testHardcodedArchiverDataDecodes() { switch HardcodedDataTestMode.mode { case .printStrings: for (idx, (constant, _)) in MessageSticker.constants.enumerated() { let serializedArchiver = try! NSKeyedArchiver.archivedData( withRootObject: constant, requiringSecureCoding: false ) print("\(Self.self) constant \(idx) keyed archiver: \(serializedArchiver.base64EncodedString())") } case .runTest: for (idx, (constant, archiverData)) in MessageSticker.constants.enumerated() { do { let deserialized = try NSKeyedUnarchiver.unarchivedObject( ofClass: MessageSticker.self, from: archiverData, requiringSecureCoding: false )! try deserialized.validate(against: constant) } catch ValidatableModelError.failedToValidate { XCTFail("Failed to validate NSKeyedArchiver-decoded model for constant \(idx)") } catch { XCTFail("Unexpected error for constant \(idx)") } } } } } extension MessageSticker { static let packId1 = Randomness.generateRandomBytes(16) static let packKey1 = Randomness.generateRandomBytes(Int32(StickerManager.packKeyLength)) static let packId2 = Randomness.generateRandomBytes(16) static let packKey2 = Randomness.generateRandomBytes(Int32(StickerManager.packKeyLength)) static let constants: [(MessageSticker, base64NSArchiverData: Data)] = [ // A simple one ( MessageSticker.withLegacyAttachment( info: StickerInfo( packId: Data(base64Encoded: "ByAo5vOcOnEljMtdQZKbjw==")!, packKey: Data(base64Encoded: "LA/Rzmg5N+24+IUifBszxD2f+7jRGIPRX9PnrhubNl4=")!, stickerId: 1 ), legacyAttachmentId: "1234", emoji: nil ), Data(base64Encoded: "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGqCwwVFh8gISIpKlUkbnVsbNQNDg8QERITFFxhdHRhY2htZW50SWRUaW5mb18QD01UTE1vZGVsVmVyc2lvblYkY2xhc3OACIADgAKACRAA1RAXGBkPGhscHRNZc3RpY2tlcklkV3BhY2tLZXlWcGFja0lkgAeABoAEgAWAAk8QICwP0c5oOTftuPiFInwbM8Q9n/u40RiD0V/T564bmzZeTxAQByAo5vOcOnEljMtdQZKbjxAB0iMkJSZaJGNsYXNzbmFtZVgkY2xhc3Nlc1tTdGlja2VySW5mb6MlJyhYTVRMTW9kZWxYTlNPYmplY3RUMTIzNNIjJCssXxAfU2lnbmFsU2VydmljZUtpdC5NZXNzYWdlU3RpY2tlcqMtJyhfEB9TaWduYWxTZXJ2aWNlS2l0Lk1lc3NhZ2VTdGlja2VyAAgAEQAaACQAKQAyADcASQBMAFEAUwBeAGQAbQB6AH8AkQCYAJoAnACeAKAAogCtALcAvwDGAMgAygDMAM4A0ADzAQYBCAENARgBIQEtATEBOgFDAUgBTQFvAXMAAAAAAAACAQAAAAAAAAAuAAAAAAAAAAAAAAAAAAABlQ==")! ), // Empty attachment id ( MessageSticker.withLegacyAttachment( info: StickerInfo( packId: Data(base64Encoded: "XWpgH3HGIDpohoaH7oDBng==")!, packKey: Data(base64Encoded: "xl88Kghch7SIC/Qa85m65XI5ehzN6djU4E3nc/fGHSU=")!, stickerId: 3 ), legacyAttachmentId: "", emoji: "a" ), Data(base64Encoded: "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGrCwwXGBkiIyQlLC1VJG51bGzVDQ4PEBESExQVFlRpbmZvVWVtb2ppXxAPTVRMTW9kZWxWZXJzaW9uXGF0dGFjaG1lbnRJZFYkY2xhc3OABIADgAKACYAKEABRYdURGhscDx0eHyAUWXN0aWNrZXJJZFdwYWNrS2V5VnBhY2tJZIAIgAeABYAGgAJPECDGXzwqCFyHtIgL9Brzmbrlcjl6HM3p2NTgTedz98YdJU8QEF1qYB9xxiA6aIaGh+6AwZ4QA9ImJygpWiRjbGFzc25hbWVYJGNsYXNzZXNbU3RpY2tlckluZm+jKCorWE1UTE1vZGVsWE5TT2JqZWN0UNImJy4vXxAfU2lnbmFsU2VydmljZUtpdC5NZXNzYWdlU3RpY2tlcqMwKitfEB9TaWduYWxTZXJ2aWNlS2l0Lk1lc3NhZ2VTdGlja2VyAAgAEQAaACQAKQAyADcASQBMAFEAUwBfAGUAcAB1AHsAjQCaAKEAowClAKcAqQCrAK0ArwC6AMQAzADTANUA1wDZANsA3QEAARMBFQEaASUBLgE6AT4BRwFQAVEBVgF4AXwAAAAAAAACAQAAAAAAAAAxAAAAAAAAAAAAAAAAAAABng==")! ), // Nil attachment id ( MessageSticker.withForeignReferenceAttachment( info: StickerInfo( packId: Data(base64Encoded: "XWpgH3HGIDpohoaH7oDBng==")!, packKey: Data(base64Encoded: "xl88Kghch7SIC/Qa85m65XI5ehzN6djU4E3nc/fGHSU=")!, stickerId: 3 ), emoji: "b" ), Data(base64Encoded: "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGqCwwVFhcgISIjKlUkbnVsbNQNDg8QERITFFRpbmZvVWVtb2ppXxAPTVRMTW9kZWxWZXJzaW9uViRjbGFzc4AEgAOAAoAJEABRYtUQGBkaDxscHR4TWXN0aWNrZXJJZFdwYWNrS2V5VnBhY2tJZIAIgAeABYAGgAJPECDGXzwqCFyHtIgL9Brzmbrlcjl6HM3p2NTgTedz98YdJU8QEF1qYB9xxiA6aIaGh+6AwZ4QA9IkJSYnWiRjbGFzc25hbWVYJGNsYXNzZXNbU3RpY2tlckluZm+jJigpWE1UTE1vZGVsWE5TT2JqZWN00iQlKyxfEB9TaWduYWxTZXJ2aWNlS2l0Lk1lc3NhZ2VTdGlja2Vyoy0oKV8QH1NpZ25hbFNlcnZpY2VLaXQuTWVzc2FnZVN0aWNrZXIACAARABoAJAApADIANwBJAEwAUQBTAF4AZABtAHIAeACKAJEAkwCVAJcAmQCbAJ0AqACyALoAwQDDAMUAxwDJAMsA7gEBAQMBCAETARwBKAEsATUBPgFDAWUBaQAAAAAAAAIBAAAAAAAAAC4AAAAAAAAAAAAAAAAAAAGL")! ), ] func validate(against: MessageSticker) throws { guard info == against.info, legacyAttachmentId == against.legacyAttachmentId, emoji == against.emoji else { throw ValidatableModelError.failedToValidate } } }