import BitFoundation import Foundation import Testing @testable import bitchat @Suite("BLE outbound fragment planner tests") struct BLEOutboundFragmentPlannerTests { @Test("planner splits packets and preserves reassembled payload") func plannerSplitsAndReassemblesPacket() throws { let packet = makePacket(payload: makePayload(count: 384)) let request = BLEOutboundFragmentTransferRequest( packet: packet, pad: false, maxChunk: 128, directedPeer: nil, transferId: nil ) let plan = try #require(BLEOutboundFragmentPlanner.makePlan( for: request, defaultChunkSize: 256, bleMaxMTU: 512, fragmentID: Data(repeating: 0xA1, count: 8) )) let headers = try plan.fragmentPackets.map { try #require(BLEFragmentHeader(packet: $0)) } let reassembled = headers.reduce(into: Data()) { data, header in data.append(header.fragmentData) } let decoded = try #require(BinaryProtocol.decode(reassembled)) #expect(plan.fragmentVersion == 1) #expect(plan.chunkSize == 128) #expect(plan.spacingMs == TransportConfig.bleFragmentSpacingMs) #expect(headers.map(\.index) == Array(0.. BLEOutboundFragmentPlan { let packet = BitchatPacket( type: MessageType.noiseEncrypted.rawValue, senderID: Data(hexString: "0011223344556677") ?? Data(), recipientID: Data(hexString: "8877665544332211"), timestamp: 0x0102030405, payload: Data(maxPayload.prefix(payloadCount)), signature: nil, ttl: 3, version: 2 ) return try #require(BLEOutboundFragmentPlanner.makePlan( for: BLEOutboundFragmentTransferRequest( packet: packet, pad: false, maxChunk: nil, directedPeer: PeerID(str: "8877665544332211"), transferId: "boundary" ), defaultChunkSize: TransportConfig.bleDefaultFragmentSize, bleMaxMTU: 512, fragmentID: Data(repeating: 0xD4, count: 8) )) } func firstPlan(withAtLeast target: Int) throws -> BLEOutboundFragmentPlan { var low = 1 var high = maxPayload.count while low < high { let mid = low + (high - low) / 2 if try plan(payloadCount: mid).totalFragments >= target { high = mid } else { low = mid + 1 } } return try plan(payloadCount: low) } let at256 = try firstPlan(withAtLeast: 256) let at257 = try firstPlan(withAtLeast: 257) #expect(at256.totalFragments == 256) #expect(BLEOutboundFragmentPlanner.isPrivateMediaV1Compatible(at256)) #expect(at257.totalFragments == 257) #expect(!BLEOutboundFragmentPlanner.isPrivateMediaV1Compatible(at257)) } private func makePacket( payload: Data, route: [Data]? = nil, isRSR: Bool = false ) -> BitchatPacket { BitchatPacket( type: MessageType.message.rawValue, senderID: Data([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]), recipientID: nil, timestamp: 0x0102030405, payload: payload, signature: nil, ttl: 3, route: route, isRSR: isRSR ) } private func makePayload(count: Int, seed: UInt64 = 0xABCD_1234) -> Data { var state = seed return Data((0..> 32) }) } }