Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/ThreemaFrameworkTests/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 39 kB image not shown  

Quelle  MessageDecoderTests.swift   Sprache: JAVA

 

import ThreemaEssentials

import ThreemaProtocols
import XCTest

@testable import ThreemaFramework

final class MessageDecoderTests: XCTestCase {

    private var testDatabase: TestDatabase!
    private var databaseCnx: DatabaseContextProtocol!

    override func setUpWithError() throws {
        AppGroup.setGroupID("group.ch.threema")

        testDatabase = TestDatabase()
        databaseCnx = testDatabase.context
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    /// Should return nil for invalid messages
    func testDecodeInvalidMessage() {
        let type: Int32 = MSGTYPE_LOCATION
        let data = Data("test".utf8)

        let result = MessageDecoder.decode(type, body: data)

        XCTAssertNil(result)
    }

    /// Should return unkown type message for unknown types
    func testDecodeUnknownType() {
        let type: Int32 = 0xFF
        let data = Data("test".utf8)

        let result = MessageDecoder.decode(type, body: data)

        XCTAssertTrue(result is UnknownTypeMessage)
    }
    
    func testDecodeBoxAudioMessage() {
        let msg = BoxAudioMessage()
        msg.duration = 1
        msg.audioBlobID = Data(BytesUtility.padding([], pad: 0x03, length: ThreemaProtocol.blobIDLength))
        msg.audioSize = 10
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x04, length: Int(kBlobKeyLen)))
        
        let result = MessageDecoder.decode(MSGTYPE_AUDIO, body: msg.body()) as? BoxAudioMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.duration, msg.duration)
        XCTAssertEqual(result?.audioBlobID, msg.audioBlobID)
        XCTAssertEqual(result?.audioSize, msg.audioSize)
        XCTAssertEqual(result?.encryptionKey, msg.encryptionKey)
    }

    func testDecodeDeliveryReceiptMessage() {
        let msg = DeliveryReceiptMessage()
        msg.receiptMessageIDs = [Data(BytesUtility.padding([], pad: 0xEF, length: ThreemaProtocol.messageIDLength))]
        msg.receiptType = .read
        
        let result = MessageDecoder.decode(MSGTYPE_DELIVERY_RECEIPT, body: msg.body()) as? DeliveryReceiptMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.receiptMessageIDs.count, 1)
        XCTAssertEqual(result?.receiptType, msg.receiptType)
    }
    
    func testDecodeBoxBallotCreateMessage() {
        let msg = newBoxBallotCreateMessage(["type": "ballot create"])
        let result = MessageDecoder.decode(MSGTYPE_BALLOT_CREATE, body: msg.body()) as? BoxBallotCreateMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.ballotID, msg.ballotID)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeBoxUpdateExtistingBallot() throws {
        let myIdentityStoreMock = MyIdentityStoreMock()

        let expectedResults = [
            ["Choice 1", "Choice 2", [
                "d": "Testtitle",
                "t": 0,
                "s": 0,
                "c": [
                    ["i": 2_222_222, "n": "Choice 1", "o": 0] as [String: Any],
                    ["i": 2_222_223, "n": "Choice 2", "o": 1]
                ],
                "o": 0,
                "a": 0,
            ] as [String: Any]] as [Any],
            [
                "Choice 1",
                "Choice 2",
                [
                    "d": "Testtitle 2",
                    "t": 0,
                    "s": 0,
                    "c": [
                        ["i": 2_222_224, "n": "Choice 3", "o": 0] as [String: Any],
                        ["i": 2_222_225, "n": "Choice 4", "o": 1]
                    ],
                    "o": 0,
                    "a": 0,
                ] as [String: Any],
            ],
        ]

        let (_, conversation) = createConversation()
        let ballotMessageDecoder =
            BallotMessageDecoder(EntityManager(databaseContext: databaseCnx, isRemoteSecretEnabled: false))

        for result in expectedResults {
            let msg = newBoxBallotCreateMessage(result[2])

            let boxBallotCreateMessage = try XCTUnwrap(
                MessageDecoder.decode(
                    MSGTYPE_BALLOT_CREATE,
                    body: msg.body()
                ) as? BoxBallotCreateMessage
            )
            boxBallotCreateMessage.fromIdentity = "ECHOECHO"

            let expect = expectation(description: "Decode and create ballot")

            var ballotMessage: BallotMessageEntity?
            ballotMessageDecoder!.decodeCreateBallot(
                fromBox: boxBallotCreateMessage,
                sender: nil,
                conversation: conversation,
                onCompletion: { messageObject in
                    do {
                        let message = try XCTUnwrap(messageObject as? BallotMessageEntity)
                        ballotMessage = message
                        expect.fulfill()
                    }
                    catch {
                        XCTFail("\(error)")
                    }
                },
                onError: { error in
                    XCTFail("\(error)")
                    expect.fulfill()
                }
            )

            wait(for: [expect], timeout: 3)

            checkBallotResult(ballotMessage: ballotMessage, result: result)
        }
    }

    func testDecodeBoxCloseExistingBallot() throws {
        let myIdentityStoreMock = MyIdentityStoreMock()

        let expectedResults = [
            ["Choice 1", "Choice 2", 0, [
                "d": "Testtitle",
                "t": 0,
                "s": 0,
                "c": [
                    ["i": 2_222_222, "n": "Choice 1", "o": 0] as [String: Any],
                    ["i": 2_222_223, "n": "Choice 2", "o": 1]
                ],
                "o": 0,
                "a": 0,
            ] as [String: Any]] as [Any],
            [
                "Choice 1",
                "Choice 2",
                1,
                [
                    "d": "Testtitle",
                    "t": 0,
                    "s": 1,
                    "c": [
                        ["i": 2_222_222, "n": "Choice 1", "o": 0] as [String: Any],
                        ["i": 2_222_223, "n": "Choice 2", "o": 1]
                    ],
                    "o": 0,
                    "a": 1,
                ] as [String: Any],
            ],
        ]

        let (_, conversation) = createConversation()
        let ballotMessageDecoder =
            BallotMessageDecoder(EntityManager(databaseContext: databaseCnx, isRemoteSecretEnabled: false))

        for result in expectedResults {
            let msg = newBoxBallotCreateMessage(result[3])

            let boxBallotCreateMessage = try XCTUnwrap(
                MessageDecoder.decode(
                    MSGTYPE_BALLOT_CREATE,
                    body: msg.body()
                ) as? BoxBallotCreateMessage
            )
            boxBallotCreateMessage.fromIdentity = "ECHOECHO"

            let expect = expectation(description: "Decode and create ballot")

            var ballotMessage: BallotMessageEntity?
            ballotMessageDecoder!.decodeCreateBallot(
                fromBox: boxBallotCreateMessage,
                sender: nil,
                conversation: conversation,
                onCompletion: { messageObject in
                    do {
                        let message = try XCTUnwrap(messageObject as? BallotMessageEntity)
                        ballotMessage = message
                        expect.fulfill()
                    }
                    catch {
                        XCTFail("\(error)")
                    }
                },
                onError: { error in
                    XCTFail("\(error)")
                    expect.fulfill()
                }
            )

            wait(for: [expect], timeout: 3)

            XCTAssertEqual(ballotMessage?.ballotState, result[2] as? NSNumber)

            checkBallotResult(ballotMessage: ballotMessage, result: result)
        }
    }

    func testDecodeBoxCloseWrongExistingBallot() throws {
        let myIdentityStoreMock = MyIdentityStoreMock()

        let expectedResults = [
            // Initial Message
            [
                "Choice 1", // Expected Result
                "Choice 2", // Expected 2nd Choice
                0,
                "Testtitle",
                [
                    "d": "Testtitle",
                    "t": 0,
                    "s": 0,
                    "c": [
                        [
                            "i": 2_222_222,
                            "n": "Choice 1",
                            "o": 0,
                        ] as [String: Any],
                        [
                            "i": 2_222_223,
                            "n": "Choice 2",
                            "o": 1,
                        ],
                    ],
                    "o": 0,
                    "a": 0,
                ] as [String: Any],
            ] as [Any],
            // Result Message
            [
                "Choice 4", // Expected Result
                "Choice 3", // Expected 2nd Choice
                1,
                "Testtitle",
                [
                    "d": "Testtitle 1",
                    "t": 0,
                    "s": 1,
                    "c": [
                        [
                            "i": 2_222_222,
                            "n": "Choice 3",
                            "o": 1,
                        ] as [String: Any],
                        [
                            "i": 2_222_223,
                            "n": "Choice 4",
                            "o": 0,
                        ],
                    ],
                    "o": 0,
                    "a": 1,
                ] as [String: Any],
            ],
        ]

        let (_, conversation) = createConversation()
        let ballotMessageDecoder =
            BallotMessageDecoder(EntityManager(databaseContext: databaseCnx, isRemoteSecretEnabled: false))

        // Initial Incoming Ballot Message
        let initialResult = expectedResults[0]
        let initialMessage = newBoxBallotCreateMessage(initialResult[4])

        let boxBallotCreateInitialMessage = try XCTUnwrap(
            MessageDecoder.decode(
                MSGTYPE_BALLOT_CREATE,
                body: initialMessage.body()
            ) as? BoxBallotCreateMessage
        )
        boxBallotCreateInitialMessage.fromIdentity = "ECHOECHO"

        let expectInitial = expectation(description: "Decode and create initial ballot")

        var ballotInitialMessage: BallotMessageEntity?
        ballotMessageDecoder?.decodeCreateBallot(
            fromBox: boxBallotCreateInitialMessage,
            sender: nil,
            conversation: conversation,
            onCompletion: { messageObject in
                do {
                    let message = try XCTUnwrap(messageObject as? BallotMessageEntity)
                    ballotInitialMessage = message
                    expectInitial.fulfill()
                }
                catch {
                    XCTFail("\(error)")
                }
            },
            onError: { error in
                XCTFail("\(error)")
                expectInitial.fulfill()
            }
        )

        wait(for: [expectInitial], timeout: 3)

        // Check Initial Choices exist
        let initialChoicesSet = (ballotInitialMessage?.ballot?.choices!)! as NSSet
        let initialChoicesArray = initialChoicesSet.allObjects as! [BallotChoiceEntity]
        let initialChoicesSorted = initialChoicesArray.sorted { $0.orderPosition!.intValue <= $1.orderPosition!.intValue
        }

        // Most Voted
        let inititalChoice1 = initialChoicesSorted.first!
        // Less Voted
        let inititalChoice2 = initialChoicesSorted.last!

        XCTAssertEqual(inititalChoice1.name, initialResult[0] as? String)
        XCTAssertEqual(inititalChoice2.name, initialResult[1] as? String)

        // Closing Ballot Message With different Results
        let differentResult = expectedResults[1]
        let resultMessage = newBoxBallotCreateMessage(differentResult[4])

        let boxBallotCreateResultMessage = try XCTUnwrap(
            MessageDecoder.decode(
                MSGTYPE_BALLOT_CREATE,
                body: resultMessage.body()
            ) as? BoxBallotCreateMessage
        )
        boxBallotCreateResultMessage.fromIdentity = "ECHOECHO"

        let expect = expectation(description: "Decode and create ballot")

        ballotMessageDecoder?.decodeCreateBallot(
            fromBox: boxBallotCreateResultMessage,
            sender: nil,
            conversation: conversation,
            onCompletion: { _ in
                expect.fulfill()
            },
            onError: { error in
                XCTFail("\(error)")
                expect.fulfill()
            }
        )

        wait(for: [expect], timeout: 3)

        // Check Results Message Overrides Initial (Local) Message
        let resultChoicesSet = (ballotInitialMessage?.ballot?.choices!)! as NSSet
        let resultChoicesArray = resultChoicesSet.allObjects as! [BallotChoiceEntity]
        let resultChoicesSorted = resultChoicesArray.sorted { $0.orderPosition!.intValue <= $1.orderPosition!.intValue }

        // Most Voted
        let resultChoice1 = resultChoicesSorted.first!
        // Less Voted
        let resultChoice2 = resultChoicesSorted.last!

        XCTAssertEqual(resultChoice1.name, differentResult[0] as? String)
        XCTAssertEqual(resultChoice2.name, differentResult[1] as? String)
    }
    
    private func createConversation() -> (ContactEntity, ConversationEntity) {
        var contact: ContactEntity!
        var conversation: ConversationEntity!
        
        let databasePreparer = testDatabase.preparer
        databasePreparer.save {
            contact = databasePreparer.createContact(publicKey: Data([1]), identity: "ECHOECHO")
            
            conversation = databasePreparer
                .createConversation(typing: false, unreadMessageCount: 0, visibility: .default) { conversation in
                    conversation.contact = contact
                }
        }
        
        return (contact, conversation)
    }
    
    func testDecodeBoxBallotVoteMessage() {
        let msg = BoxBallotVoteMessage()
        msg.ballotCreator = "TESTID12"
        msg.ballotID = Data(BytesUtility.padding([], pad: 0x99, length: ThreemaProtocol.ballotIDLength))
        msg.jsonChoiceData = Data("{type: 'ballot vote'}".utf8)

        let result = MessageDecoder.decode(MSGTYPE_BALLOT_VOTE, body: msg.body()) as? BoxBallotVoteMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.ballotCreator, msg.ballotCreator)
        XCTAssertEqual(result?.ballotID, msg.ballotID)
        XCTAssertEqual(result?.jsonChoiceData, msg.jsonChoiceData)
    }
    
    func testDecodeBoxFileMessage() {
        let msg = BoxFileMessage()
        msg.jsonData = Data("{type: 'file'}".utf8)
        
        let result = MessageDecoder.decode(MSGTYPE_FILE, body: msg.body()) as? BoxFileMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeBoxImageMessage() {
        let msg = BoxImageMessage()
        msg.blobID = Data(BytesUtility.padding([], pad: 0x01, length: ThreemaProtocol.blobIDLength))
        msg.imageNonce = Data(BytesUtility.padding([], pad: 0x02, length: Int(kNonceLen)))
        msg.size = 3

        let result = MessageDecoder.decode(MSGTYPE_IMAGE, body: msg.body()) as? BoxImageMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.blobID, msg.blobID)
        XCTAssertEqual(result?.imageNonce, msg.imageNonce)
        XCTAssertEqual(result?.size, 3)
    }
    
    func testDecodeBoxLocationMessage() throws {
        let msg = Data("47.201515,8.783403,65.000000".utf8)
        
        let result = try XCTUnwrap(MessageDecoder.decode(MSGTYPE_LOCATION, body: msg) as? BoxLocationMessage)
        
        XCTAssertEqual(result.latitude, 47.201515)
        XCTAssertEqual(result.longitude, 8.783403)
        XCTAssertEqual(result.accuracy, 65.000000)
    }
    
    func testDecodeBoxLocationMessageNoPoiName() throws {
        let msg = Data("47.201515,8.783403,65.000000\n\ntestAddress".utf8)
        
        let result = try XCTUnwrap(MessageDecoder.decode(MSGTYPE_LOCATION, body: msg) as? BoxLocationMessage)
        
        XCTAssertEqual(result.latitude, 47.201515)
        XCTAssertEqual(result.longitude, 8.783403)
        XCTAssertEqual(result.accuracy, 65.000000)
        XCTAssertEqual(result.poiName, "")
        XCTAssertEqual(result.poiAddress, "testAddress")
    }
    
    func testDecodeBoxLocationMessageAddress() throws {
        let msg = Data("47.201515,8.783403,65.000000\ntestName\ntestAddress\\nline2".utf8)
        
        let result = try XCTUnwrap(MessageDecoder.decode(MSGTYPE_LOCATION, body: msg) as? BoxLocationMessage)
        
        XCTAssertEqual(result.latitude, 47.201515)
        XCTAssertEqual(result.longitude, 8.783403)
        XCTAssertEqual(result.accuracy, 65.000000)
        XCTAssertEqual(result.poiName, "testName")
        XCTAssertEqual(result.poiAddress, "testAddress\nline2")
    }
    
    func testDecodeBoxTextMessage() throws {
        let msg = BoxTextMessage()
        msg.text = "Muttis diweiss"
        
        let result = MessageDecoder.decode(MSGTYPE_TEXT, body: msg.body()) as? BoxTextMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.text, "Muttis diweiss")
        XCTAssertNil(result?.quotedMessageID)
        XCTAssertEqual(
            try String(data: XCTUnwrap(result?.quotedBody()), encoding: .utf8),
            "Muttis diweiss"
        )
    }
    
    func testDecodeBoxTextMessageQuoted() throws {
        let expectedQuotedMessageID = BytesUtility.generateRandomBytes(length: ThreemaProtocol.messageIDLength)!
        let expectedQuotedText = QuoteUtil.generateText("Muttis diweiss", quotedID: expectedQuotedMessageID)

        let msg = BoxTextMessage()
        msg.text = expectedQuotedText
        msg.quotedMessageID = expectedQuotedMessageID

        let result = MessageDecoder.decode(MSGTYPE_TEXT, body: msg.body()) as? BoxTextMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.text, "Muttis diweiss")
        XCTAssertEqual(result?.quotedMessageID, expectedQuotedMessageID)
        XCTAssertEqual(
            try String(data: XCTUnwrap((XCTUnwrap(result) as QuotedMessageProtocol).quotedBody()), encoding: .utf8),
            expectedQuotedText
        )
    }

    func testDecodeBoxVideoMessage() {
        let msg = BoxVideoMessage()
        msg.duration = 1
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x02, length: Int(kBlobKeyLen)))
        msg.thumbnailBlobID = Data(BytesUtility.padding([], pad: 0x03, length: ThreemaProtocol.blobIDLength))
        msg.thumbnailSize = 3
        msg.videoBlobID = Data(BytesUtility.padding([], pad: 0x04, length: ThreemaProtocol.blobIDLength))
        msg.videoSize = 2
        
        let result = MessageDecoder.decode(MSGTYPE_VIDEO, body: msg.body()) as? BoxVideoMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.duration, msg.duration)
        XCTAssertEqual(result?.encryptionKey, msg.encryptionKey)
        XCTAssertEqual(result?.thumbnailBlobID, msg.thumbnailBlobID)
        XCTAssertEqual(result?.thumbnailSize, msg.thumbnailSize)
        XCTAssertEqual(result?.videoBlobID, msg.videoBlobID)
        XCTAssertEqual(result?.videoSize, msg.videoSize)
    }
    
    func testDecodeBoxVoIPCallAnswerMessage() {
        let msg = BoxVoIPCallAnswerMessage() // Data()
        msg.jsonData = Data("{type: 'call answer'}".utf8)
        
        let result = MessageDecoder.decode(MSGTYPE_VOIP_CALL_ANSWER, body: msg.body()) as? BoxVoIPCallAnswerMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeBoxVoIPCallHangupMessage() {
        let result = MessageDecoder.decode(MSGTYPE_VOIP_CALL_HANGUP, body: Data()) as? BoxVoIPCallHangupMessage
        
        XCTAssertNotNil(result)
    }
    
    func testDecodeBoxVoIPCallIceCandidatesMessage() {
        let msg = BoxVoIPCallIceCandidatesMessage()
        msg.jsonData = Data("{type: 'call icecandidate'}".utf8)
        
        let result = MessageDecoder.decode(
            MSGTYPE_VOIP_CALL_ICECANDIDATE,
            body: msg.body()
        ) as? BoxVoIPCallIceCandidatesMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeBoxVoIPCallOfferMessage() {
        let msg = BoxVoIPCallOfferMessage()
        msg.jsonData = Data("{type: 'call offer'}".utf8)
        
        let result = MessageDecoder.decode(MSGTYPE_VOIP_CALL_OFFER, body: msg.body()) as? BoxVoIPCallOfferMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeBoxVoIPCallRingingMessage() {
        let msg = Data()
        
        let result = MessageDecoder.decode(MSGTYPE_VOIP_CALL_RINGING, body: msg) as? BoxVoIPCallRingingMessage
        
        XCTAssertNotNil(result)
    }
    
    func testDecodeContactDeletePhotoMessage() {
        let msg = Data()
        
        let result = MessageDecoder.decode(MSGTYPE_CONTACT_DELETE_PHOTO, body: msg) as? ContactDeletePhotoMessage
        
        XCTAssertNotNil(result)
    }
    
    func testDecodeContactRequestPhotoMessage() {
        let msg = Data()
        
        let result = MessageDecoder.decode(MSGTYPE_CONTACT_REQUEST_PHOTO, body: msg) as? ContactRequestPhotoMessage
        
        XCTAssertNotNil(result)
    }
    
    func testDecodeContactSetPhotoMessage() {
        let msg = ContactSetPhotoMessage()
        msg.blobID = Data(BytesUtility.padding([], pad: 0x68, length: ThreemaProtocol.blobIDLength))
        msg.size = 10
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x91, length: Int(kBlobKeyLen)))
        
        let result = MessageDecoder.decode(MSGTYPE_CONTACT_SET_PHOTO, body: msg.body()) as? ContactSetPhotoMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.blobID, msg.blobID)
        XCTAssertEqual(result?.size, msg.size)
        XCTAssertEqual(result?.encryptionKey, msg.encryptionKey)
    }

    func testDecodeDeleteGroupMessage() throws {
        var expectedDeleteMessage = CspE2e_DeleteMessage()
        expectedDeleteMessage.messageID = try BytesUtility.generateMessageID().littleEndian()

        let msg = DeleteGroupMessage()
        msg.groupCreator = "ECHOECHO"
        msg.groupID = BytesUtility.generateGroupID()
        msg.decoded = expectedDeleteMessage

        let result = MessageDecoder.decode(MSGTYPE_GROUP_DELETE, body: msg.body()) as? DeleteGroupMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.decoded?.messageID, expectedDeleteMessage.messageID)
    }

    func testDecodeDeleteMessage() throws {
        var expectedDeleteMessage = CspE2e_DeleteMessage()
        expectedDeleteMessage.messageID = try BytesUtility.generateMessageID().littleEndian()

        let msg = DeleteMessage()
        msg.decoded = expectedDeleteMessage

        let result = MessageDecoder.decode(MSGTYPE_DELETE, body: msg.body()) as? DeleteMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.decoded?.messageID, expectedDeleteMessage.messageID)
    }

    func testDecodeEditGroupMessage() throws {
        var expectedEditMessage = CspE2e_EditMessage()
        expectedEditMessage.messageID = try BytesUtility.generateMessageID().littleEndian()
        expectedEditMessage.text = "Test 123"

        let msg = EditGroupMessage()
        msg.groupCreator = "ECHOECHO"
        msg.groupID = BytesUtility.generateGroupID()
        msg.decoded = expectedEditMessage

        let result = MessageDecoder.decode(MSGTYPE_GROUP_EDIT, body: msg.body()) as? EditGroupMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.decoded?.messageID, expectedEditMessage.messageID)
        XCTAssertEqual(result?.decoded?.text, expectedEditMessage.text)
    }

    func testDecodeEditMessage() throws {
        var expectedEditMessage = CspE2e_EditMessage()
        expectedEditMessage.messageID = try BytesUtility.generateMessageID().littleEndian()
        expectedEditMessage.text = "Test 123"

        let msg = EditMessage()
        msg.decoded = expectedEditMessage

        let result = MessageDecoder.decode(MSGTYPE_EDIT, body: msg.body()) as? EditMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.decoded?.messageID, expectedEditMessage.messageID)
        XCTAssertEqual(result?.decoded?.text, expectedEditMessage.text)
    }
    
    func testDecodeGroupReactionMessage() throws {
        var expectedReactionMessage = CspE2e_Reaction()
        expectedReactionMessage.messageID = try BytesUtility.generateMessageID().littleEndian()
        expectedReactionMessage.action = .apply(Data("✌��".utf8))

        let msg = GroupReactionMessage()
        msg.groupCreator = "ECHOECHO"
        msg.groupID = BytesUtility.generateGroupID()
        msg.decoded = expectedReactionMessage

        let result = MessageDecoder.decode(MSGTYPE_GROUP_REACTION, body: msg.body()) as? GroupReactionMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.decoded?.messageID, expectedReactionMessage.messageID)
        XCTAssertEqual(result?.decoded?.action, expectedReactionMessage.action)
    }

    func testDecodeReactionMessage() throws {
        var expectedReactionMessage = CspE2e_Reaction()
        expectedReactionMessage.messageID = try BytesUtility.generateMessageID().littleEndian()
        expectedReactionMessage.action = .apply(Data("✌��".utf8))

        let msg = ReactionMessage()
        msg.decoded = expectedReactionMessage

        let result = MessageDecoder.decode(MSGTYPE_REACTION, body: msg.body()) as? ReactionMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.decoded?.messageID, expectedReactionMessage.messageID)
        XCTAssertEqual(result?.decoded?.action, expectedReactionMessage.action)
    }

    func testDecodeGroupAudioMessage() {
        let msg = GroupAudioMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x67, length: ThreemaProtocol.groupIDLength))
        msg.duration = 1
        msg.audioBlobID = Data(BytesUtility.padding([], pad: 0x03, length: ThreemaProtocol.blobIDLength))
        msg.audioSize = 10
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x04, length: Int(kBlobKeyLen)))

        let result = MessageDecoder.decode(MSGTYPE_GROUP_AUDIO, body: msg.body()) as? GroupAudioMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.duration, msg.duration)
        XCTAssertEqual(result?.audioBlobID, msg.audioBlobID)
        XCTAssertEqual(result?.audioSize, msg.audioSize)
        XCTAssertEqual(result?.encryptionKey, msg.encryptionKey)
    }
    
    func testDecodeGroupBallotCreateMessage() {
        let msg = GroupBallotCreateMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x11, length: ThreemaProtocol.groupIDLength))
        msg.ballotID = Data(BytesUtility.padding([], pad: 0x22, length: ThreemaProtocol.ballotIDLength))
        msg.jsonData = Data("{type: 'group ballot create'}".utf8)
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_BALLOT_CREATE, body: msg.body()) as? GroupBallotCreateMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.ballotID, msg.ballotID)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeGroupBallotVoteMessage() {
        let msg = GroupBallotVoteMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x66, length: ThreemaProtocol.groupIDLength))
        msg.ballotCreator = "TESTID34"
        msg.ballotID = Data(BytesUtility.padding([], pad: 0x55, length: ThreemaProtocol.ballotIDLength))
        msg.jsonChoiceData = Data("{type: 'group ballot vote'}".utf8)
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_BALLOT_VOTE, body: msg.body()) as? GroupBallotVoteMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.ballotCreator, msg.ballotCreator)
        XCTAssertEqual(result?.ballotID, msg.ballotID)
        XCTAssertEqual(result?.jsonChoiceData, msg.jsonChoiceData)
    }
    
    func testDecodeGroupCreateMessage() {
        let msg = GroupCreateMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x09, length: ThreemaProtocol.groupIDLength))
        msg.groupMembers = ["ECHOECHO"]
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_CREATE, body: msg.body()) as? GroupCreateMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.groupMembers.count, 1)
        XCTAssertEqual(result?.groupMembers[0] as? String, "ECHOECHO")
    }
    
    func testDecodeGroupDeletePhotoMessage() {
        let msg = GroupDeletePhotoMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x13, length: ThreemaProtocol.groupIDLength))
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_DELETE_PHOTO, body: msg.body()) as? GroupDeletePhotoMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
    }
    
    func testDecodeGroupDeliveryReceiptMessage() {
        let msg = GroupDeliveryReceiptMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x13, length: ThreemaProtocol.groupIDLength))
        msg.groupCreator = "TESTID12"
        msg.receiptMessageIDs = [Data(BytesUtility.padding([], pad: 0xEF, length: ThreemaProtocol.messageIDLength))]
        msg.receiptType = ReceiptType.read.rawValue
        
        let result = MessageDecoder.decode(
            MSGTYPE_GROUP_DELIVERY_RECEIPT,
            body: msg.body()
        ) as? GroupDeliveryReceiptMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.receiptMessageIDs.count, 1)
        XCTAssertEqual(result?.receiptType, msg.receiptType)
    }
    
    func testDecodeGroupFileMessage() {
        let msg = GroupFileMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x46, length: ThreemaProtocol.groupIDLength))
        msg.jsonData = Data("{type: 'group file'}".utf8)
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_FILE, body: msg.body()) as? GroupFileMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.jsonData, msg.jsonData)
    }
    
    func testDecodeGroupImageMessage() {
        let msg = GroupImageMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x23, length: ThreemaProtocol.groupIDLength))
        msg.blobID = Data(BytesUtility.padding([], pad: 0x01, length: ThreemaProtocol.blobIDLength))
        msg.size = 3
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x03, length: Int(kBlobKeyLen)))
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_IMAGE, body: msg.body()) as? GroupImageMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.blobID, msg.blobID)
        XCTAssertEqual(result?.size, msg.size)
        XCTAssertEqual(result?.encryptionKey, msg.encryptionKey)
    }
    
    func testDecodeGroupLeaveMessage() {
        let msg = GroupLeaveMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x54, length: ThreemaProtocol.groupIDLength))
        msg.groupCreator = "TESTID12"
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_LEAVE, body: msg.body()) as? GroupLeaveMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
    }
    
    func testDecodeGroupLocationMessage() {
        var msg = Data("TESTID12".utf8)
        let groupID = Data(BytesUtility.padding([], pad: 0x12, length: ThreemaProtocol.groupIDLength))
        msg.append(groupID)
        msg.append(Data("47.201515,8.783403,65.000000".utf8))

        let result = MessageDecoder.decode(MSGTYPE_GROUP_LOCATION, body: msg) as? GroupLocationMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, groupID)
        XCTAssertEqual(result?.groupCreator, "TESTID12")
        XCTAssertEqual(result?.latitude, 47.201515)
        XCTAssertEqual(result?.longitude, 8.783403)
        XCTAssertEqual(result?.accuracy, 65.000000)
    }
    
    func testDecodeGroupRenameMessage() {
        let msg = GroupRenameMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x69, length: ThreemaProtocol.groupIDLength))
        msg.name = "Group name"
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_RENAME, body: msg.body()) as? GroupRenameMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.name, msg.name)
    }
    
    func testDecodeGroupRequestSyncMessage() {
        let msg = GroupRequestSyncMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x77, length: ThreemaProtocol.groupIDLength))
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_REQUEST_SYNC, body: msg.body()) as? GroupRequestSyncMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
    }
    
    func testDecodeGroupSetPhotoMessage() {
        let msg = GroupSetPhotoMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x50, length: ThreemaProtocol.groupIDLength))
        msg.blobID = Data(BytesUtility.padding([], pad: 0x60, length: ThreemaProtocol.blobIDLength))
        msg.size = 4
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x70, length: Int(kBlobKeyLen)))
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_SET_PHOTO, body: msg.body()) as? GroupSetPhotoMessage
        
        XCTAssertNotNil(result)
    }
    
    func testDecodeGroupTextMessage() throws {
        let msg = GroupTextMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x34, length: ThreemaProtocol.groupIDLength))
        msg.groupCreator = "TESTID12"
        msg.text = "Test text"
        
        let result = MessageDecoder.decode(MSGTYPE_GROUP_TEXT, body: msg.body()) as? GroupTextMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.text, msg.text)
        XCTAssertNil(result?.quotedMessageID)
        XCTAssertEqual(
            try String(data: XCTUnwrap(result?.quotedBody()), encoding: .utf8),
            "TESTID1244444444Test text"
        )
    }
    
    func testDecodeGroupTextMessageQuoted() throws {
        let expectedQuotedMessageID = BytesUtility.generateRandomBytes(length: ThreemaProtocol.messageIDLength)
        let expectedQuotedText = QuoteUtil.generateText("Test text", quotedID: expectedQuotedMessageID!)

        let msg = GroupTextMessage()
        msg.groupID = Data(BytesUtility.padding([], pad: 0x34, length: ThreemaProtocol.groupIDLength))
        msg.groupCreator = "TESTID12"
        msg.text = expectedQuotedText

        let result = MessageDecoder.decode(MSGTYPE_GROUP_TEXT, body: msg.body()) as? GroupTextMessage

        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.text, "Test text")
        XCTAssertEqual(result?.quotedMessageID, expectedQuotedMessageID)
        XCTAssertEqual(
            try String(data: XCTUnwrap((XCTUnwrap(result) as QuotedMessageProtocol).quotedBody()), encoding: .utf8),
            "TESTID1244444444\(expectedQuotedText)"
        )
    }

    func testDecodeGroupVideoMessage() {
        let msg = GroupVideoMessage()
        msg.groupCreator = "TESTID12"
        msg.groupID = Data(BytesUtility.padding([], pad: 0x56, length: ThreemaProtocol.groupIDLength))
        msg.duration = 1
        msg.encryptionKey = Data(BytesUtility.padding([], pad: 0x02, length: Int(kBlobKeyLen)))
        msg.thumbnailBlobID = Data(BytesUtility.padding([], pad: 0x03, length: ThreemaProtocol.blobIDLength))
        msg.thumbnailSize = 3
        msg.videoBlobID = Data(BytesUtility.padding([], pad: 0x04, length: ThreemaProtocol.blobIDLength))
        msg.videoSize = 2

        let result = MessageDecoder.decode(MSGTYPE_GROUP_VIDEO, body: msg.body()) as? GroupVideoMessage
        
        XCTAssertNotNil(result)
        XCTAssertEqual(result?.groupCreator, msg.groupCreator)
        XCTAssertEqual(result?.groupID, msg.groupID)
        XCTAssertEqual(result?.duration, msg.duration)
        XCTAssertEqual(result?.encryptionKey, msg.encryptionKey)
        XCTAssertEqual(result?.thumbnailBlobID, msg.thumbnailBlobID)
        XCTAssertEqual(result?.thumbnailSize, msg.thumbnailSize)
        XCTAssertEqual(result?.videoBlobID, msg.videoBlobID)
        XCTAssertEqual(result?.videoSize, msg.videoSize)
    }
    
    func testDecodeTypingIndicatorMessage() {
        let msg = TypingIndicatorMessage()
        msg.typing = true
        
        let result = MessageDecoder.decode(MSGTYPE_TYPING_INDICATOR, body: msg.body()) as? TypingIndicatorMessage
        
        XCTAssertNotNil(result)
        XCTAssertTrue(result!.typing)
    }
    
    private func parseJson(_ obj: Any) -> Data? {
        do {
            return try JSONSerialization.data(withJSONObject: obj, options: .prettyPrinted)
        }
        catch {
            XCTFail("Can't build json")
            return nil
        }
    }
    
    private func newBoxBallotCreateMessage(_ obj: Any) -> BoxBallotCreateMessage {
        let msg = BoxBallotCreateMessage()
        msg.ballotID = Data(BytesUtility.padding([], pad: 0x88, length: ThreemaProtocol.ballotIDLength))
        msg.jsonData = parseJson(obj)
        return msg
    }
    
    private func checkBallotResult(ballotMessage: BallotMessageEntity?, result: [Any]) {
        let allObjects = ((ballotMessage?.ballot?.choices)! as NSSet).allObjects
        let choice1 = allObjects.first as! BallotChoiceEntity
        let choice2 = allObjects.last as! BallotChoiceEntity
        
        if choice1.orderPosition == 0 {
            XCTAssertEqual(choice1.name, result[0] as? String)
            XCTAssertEqual(choice2.name, result[1] as? String)
        }
        else {
            XCTAssertEqual(choice1.name, result[1] as? String)
            XCTAssertEqual(choice2.name, result[0] as? String)
        }
    }
}

Messung
CHZG
849710093

¤ Dauer der Verarbeitung: 0.5 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.