mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 10:25:18 +00:00
175 lines
6.7 KiB
Swift
175 lines
6.7 KiB
Swift
import XCTest
|
|
@testable import bitchat
|
|
|
|
final class NotificationStreamAssemblerTests: XCTestCase {
|
|
private func makePacket(timestamp: UInt64 = 0x0102030405) -> BitchatPacket {
|
|
let sender = Data([0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77])
|
|
return BitchatPacket(
|
|
type: MessageType.message.rawValue,
|
|
senderID: sender,
|
|
recipientID: nil,
|
|
timestamp: timestamp,
|
|
payload: Data([0xDE, 0xAD, 0xBE, 0xEF]),
|
|
signature: nil,
|
|
ttl: 3
|
|
)
|
|
}
|
|
|
|
func testAssemblesSingleFrameAcrossChunks() {
|
|
var assembler = NotificationStreamAssembler()
|
|
let packet = makePacket()
|
|
guard let frame = packet.toBinaryData(padding: false) else {
|
|
return XCTFail("Failed to encode packet")
|
|
}
|
|
XCTAssertNotNil(BinaryProtocol.decode(frame))
|
|
let payloadLen = (Int(frame[12]) << 8) | Int(frame[13])
|
|
XCTAssertEqual(payloadLen, packet.payload.count)
|
|
|
|
let splitIndex = min(20, max(1, frame.count / 2))
|
|
let first = frame.prefix(splitIndex)
|
|
let second = frame.suffix(from: splitIndex)
|
|
XCTAssertEqual(first.count + second.count, frame.count)
|
|
|
|
var result = assembler.append(first)
|
|
XCTAssertTrue(result.frames.isEmpty)
|
|
XCTAssertTrue(result.droppedPrefixes.isEmpty)
|
|
XCTAssertFalse(result.reset)
|
|
|
|
result = assembler.append(second)
|
|
XCTAssertEqual(result.frames.count, 1)
|
|
XCTAssertTrue(result.droppedPrefixes.isEmpty)
|
|
XCTAssertFalse(result.reset)
|
|
|
|
guard let frameData = result.frames.first else {
|
|
return XCTFail("Missing frame data")
|
|
}
|
|
if frameData.count != frame.count {
|
|
XCTFail("Frame size mismatch: expected \(frame.count) got \(frameData.count)\nframe=\(Array(frame))\nassembled=\(Array(frameData))")
|
|
return
|
|
}
|
|
guard let decoded = BinaryProtocol.decode(frameData) else {
|
|
return XCTFail("Failed to decode frame")
|
|
}
|
|
XCTAssertEqual(decoded.type, packet.type)
|
|
XCTAssertEqual(decoded.payload, packet.payload)
|
|
XCTAssertEqual(decoded.senderID, packet.senderID)
|
|
XCTAssertEqual(decoded.timestamp, packet.timestamp)
|
|
|
|
var directAssembler = NotificationStreamAssembler()
|
|
let directResult = directAssembler.append(frame)
|
|
XCTAssertEqual(directResult.frames.first?.count, frame.count)
|
|
}
|
|
|
|
func testAssemblesMultipleFramesSequentially() {
|
|
var assembler = NotificationStreamAssembler()
|
|
let packet1 = makePacket(timestamp: 0xABC)
|
|
let packet2 = makePacket(timestamp: 0xDEF)
|
|
|
|
guard let frame1 = packet1.toBinaryData(padding: false),
|
|
let frame2 = packet2.toBinaryData(padding: false) else {
|
|
return XCTFail("Failed to encode packets")
|
|
}
|
|
|
|
var combined = Data()
|
|
combined.append(frame1)
|
|
combined.append(frame2)
|
|
let firstChunk = combined.prefix(20)
|
|
let secondChunk = combined.suffix(from: 20)
|
|
|
|
var result = assembler.append(firstChunk)
|
|
XCTAssertTrue(result.frames.isEmpty)
|
|
|
|
result = assembler.append(secondChunk)
|
|
XCTAssertEqual(result.frames.count, 2)
|
|
guard let decoded1 = BinaryProtocol.decode(result.frames[0]),
|
|
let decoded2 = BinaryProtocol.decode(result.frames[1]) else {
|
|
return XCTFail("Failed to decode frames")
|
|
}
|
|
XCTAssertEqual(decoded1.timestamp, packet1.timestamp)
|
|
XCTAssertEqual(decoded2.timestamp, packet2.timestamp)
|
|
}
|
|
|
|
func testDropsInvalidPrefixByte() {
|
|
var assembler = NotificationStreamAssembler()
|
|
let packet = makePacket(timestamp: 0xF00)
|
|
guard let frame = packet.toBinaryData(padding: false) else {
|
|
return XCTFail("Failed to encode packet")
|
|
}
|
|
var noisyFrame = Data([0x00])
|
|
noisyFrame.append(frame)
|
|
|
|
let result = assembler.append(noisyFrame)
|
|
XCTAssertEqual(result.droppedPrefixes, [0x00])
|
|
XCTAssertEqual(result.frames.count, 1)
|
|
XCTAssertFalse(result.reset)
|
|
|
|
guard let decoded = BinaryProtocol.decode(result.frames[0]) else {
|
|
return XCTFail("Failed to decode frame after drop")
|
|
}
|
|
XCTAssertEqual(decoded.timestamp, packet.timestamp)
|
|
}
|
|
|
|
func testAssemblesCompressedLargeFrame() throws {
|
|
var assembler = NotificationStreamAssembler()
|
|
|
|
let largeContent = Data(repeating: 0x41, count: 2_500_000)
|
|
let filePacket = BitchatFilePacket(
|
|
fileName: "large.bin",
|
|
fileSize: UInt64(largeContent.count),
|
|
mimeType: "application/octet-stream",
|
|
content: largeContent
|
|
)
|
|
guard let tlvPayload = filePacket.encode() else {
|
|
return XCTFail("Failed to encode file packet")
|
|
}
|
|
|
|
let senderID = Data(repeating: 0xAA, count: BinaryProtocol.senderIDSize)
|
|
let packet = BitchatPacket(
|
|
type: MessageType.fileTransfer.rawValue,
|
|
senderID: senderID,
|
|
recipientID: nil,
|
|
timestamp: 0x010203040506,
|
|
payload: tlvPayload,
|
|
signature: nil,
|
|
ttl: 3,
|
|
version: 2
|
|
)
|
|
|
|
guard let frame = packet.toBinaryData(padding: false) else {
|
|
return XCTFail("Failed to encode packet frame")
|
|
}
|
|
|
|
let flagsOffset = 1 + 1 + 1 + 8
|
|
XCTAssertLessThan(flagsOffset, frame.count)
|
|
let flags = frame[frame.startIndex + flagsOffset]
|
|
XCTAssertNotEqual(flags & BinaryProtocol.Flags.isCompressed, 0, "Frame should be compressed for large payloads")
|
|
|
|
let splitIndex = min(4096, frame.count / 2)
|
|
var result = assembler.append(frame.prefix(splitIndex))
|
|
XCTAssertTrue(result.frames.isEmpty)
|
|
|
|
result = assembler.append(frame.suffix(from: splitIndex))
|
|
XCTAssertEqual(result.frames.count, 1)
|
|
XCTAssertTrue(result.droppedPrefixes.isEmpty)
|
|
XCTAssertFalse(result.reset)
|
|
|
|
guard let assembled = result.frames.first else {
|
|
return XCTFail("Missing assembled frame")
|
|
}
|
|
XCTAssertEqual(assembled.count, frame.count)
|
|
|
|
guard let decodedPacket = BinaryProtocol.decode(assembled) else {
|
|
return XCTFail("Failed to decode compressed frame")
|
|
}
|
|
XCTAssertEqual(decodedPacket.payload.count, tlvPayload.count)
|
|
|
|
guard let decodedFile = BitchatFilePacket.decode(decodedPacket.payload) else {
|
|
return XCTFail("Failed to decode TLV payload")
|
|
}
|
|
XCTAssertEqual(decodedFile.fileName, filePacket.fileName)
|
|
XCTAssertEqual(decodedFile.mimeType, filePacket.mimeType)
|
|
XCTAssertEqual(decodedFile.content.count, largeContent.count)
|
|
XCTAssertEqual(decodedFile.content.prefix(32), largeContent.prefix(32))
|
|
}
|
|
}
|