Raise protocol coverage to 99 percent (#1058)

* Expand protocol coverage with edge-case tests

* Stabilize read receipt transport test

* Stabilize BLE duplicate packet test

---------

Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
jack
2026-03-12 17:55:41 -10:00
committed by GitHub
co-authored by jack
parent 8562a76367
commit 264a95b61a
9 changed files with 288 additions and 9 deletions
@@ -69,4 +69,25 @@ final class BinaryEncodingUtilsTests: XCTestCase {
XCTAssertNil(shortData.readFixedBytes(at: &offset, count: 2))
XCTAssertEqual(offset, 0)
}
func test_sha256Hex_andExtendedLengthStringRoundTrip() throws {
XCTAssertEqual(
Data("abc".utf8).sha256Hex(),
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
)
var data = Data()
data.appendString("hello", maxLength: 300)
var offset = 0
XCTAssertEqual(data.readString(at: &offset, maxLength: 300), "hello")
}
func test_readString_returnsNilForInvalidUTF8ExtendedPayload() {
let invalidUTF8 = Data([0x00, 0x02, 0xFF, 0xFF])
var offset = 0
XCTAssertNil(invalidUTF8.readString(at: &offset, maxLength: 300))
XCTAssertEqual(offset, invalidUTF8.count)
}
}
@@ -44,4 +44,33 @@ final class BitchatFilePacketTests: XCTestCase {
XCTAssertEqual(decoded.fileSize, UInt64(content.count))
XCTAssertEqual(decoded.content, content)
}
func testDecodeSupportsLegacyEightByteFileSizeTLV() throws {
let content = Data([0x01, 0x02, 0x03, 0x04])
var data = Data()
data.append(0x02)
data.append(contentsOf: [0x00, 0x08])
data.append(contentsOf: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00])
data.append(0x04)
data.append(contentsOf: [0x00, 0x00, 0x00, 0x04])
data.append(content)
let decoded = try XCTUnwrap(BitchatFilePacket.decode(data))
XCTAssertEqual(decoded.fileSize, 256)
XCTAssertEqual(decoded.content, content)
}
func testDecodeUsesContentCountWhenFileSizeTLVIsMissing() throws {
let content = Data([0xAA, 0xBB, 0xCC])
var data = Data()
data.append(0x04)
data.append(contentsOf: [0x00, 0x00, 0x00, 0x03])
data.append(content)
let decoded = try XCTUnwrap(BitchatFilePacket.decode(data))
XCTAssertEqual(decoded.fileSize, UInt64(content.count))
XCTAssertEqual(decoded.content, content)
}
}
@@ -0,0 +1,56 @@
import Foundation
import Testing
@testable import bitchat
struct LocationChannelTests {
@Test
func geohashChannelLevelDisplayNamesAndLegacyDecoding() throws {
for level in GeohashChannelLevel.allCases {
#expect(level.displayName.isEmpty == false)
}
#expect(try decodeLevel(from: "\"building\"") == .building)
#expect(try decodeLevel(from: "\"block\"") == .block)
#expect(try decodeLevel(from: "\"neighborhood\"") == .neighborhood)
#expect(try decodeLevel(from: "\"city\"") == .city)
#expect(try decodeLevel(from: "\"province\"") == .province)
#expect(try decodeLevel(from: "\"region\"") == .province)
#expect(try decodeLevel(from: "\"country\"") == .region)
#expect(try decodeLevel(from: "\"unknown\"") == .block)
#expect(try decodeLevel(from: "8") == .building)
#expect(try decodeLevel(from: "7") == .block)
#expect(try decodeLevel(from: "6") == .neighborhood)
#expect(try decodeLevel(from: "5") == .city)
#expect(try decodeLevel(from: "4") == .province)
#expect(try decodeLevel(from: "3") == .region)
#expect(try decodeLevel(from: "0") == .region)
#expect(try decodeLevel(from: "99") == .block)
#expect(try decodeLevel(from: "true") == .block)
}
@Test
func geohashChannelAndChannelIDExposeStableAccessors() {
let channel = GeohashChannel(level: .city, geohash: "u4pru")
#expect(channel.id == "city-u4pru")
#expect(channel.displayName.contains("u4pru"))
#expect(channel.displayName.contains(channel.level.displayName))
let mesh = ChannelID.mesh
#expect(mesh.displayName == "Mesh")
#expect(mesh.nostrGeohashTag == nil)
#expect(mesh.isMesh)
#expect(mesh.isLocation == false)
let location = ChannelID.location(channel)
#expect(location.displayName == channel.displayName)
#expect(location.nostrGeohashTag == "u4pru")
#expect(location.isMesh == false)
#expect(location.isLocation)
}
private func decodeLevel(from json: String) throws -> GeohashChannelLevel {
try JSONDecoder().decode(GeohashChannelLevel.self, from: Data(json.utf8))
}
}
+125
View File
@@ -0,0 +1,125 @@
import Foundation
import Testing
@testable import bitchat
struct PacketsTests {
@Test
func announcementPacketRoundTripsNeighborsAndSkipsUnknownTLVs() throws {
let neighbors = (0..<12).map { index in
Data(repeating: UInt8(index), count: 8)
}
let packet = AnnouncementPacket(
nickname: "alice",
noisePublicKey: Data(repeating: 0x11, count: 32),
signingPublicKey: Data(repeating: 0x22, count: 32),
directNeighbors: neighbors
)
var encoded = try #require(packet.encode())
encoded.append(makeTLV(type: 0xFF, value: Data([0xAB])))
let decoded = try #require(AnnouncementPacket.decode(from: encoded))
#expect(decoded.nickname == "alice")
#expect(decoded.noisePublicKey == Data(repeating: 0x11, count: 32))
#expect(decoded.signingPublicKey == Data(repeating: 0x22, count: 32))
#expect(decoded.directNeighbors?.count == 10)
#expect(decoded.directNeighbors?.first == neighbors.first)
#expect(decoded.directNeighbors?.last == neighbors[9])
}
@Test
func announcementPacketEncodeRejectsOversizedFieldsAndInvalidNeighborGroups() {
let oversizedNickname = String(repeating: "a", count: 256)
let validKey = Data(repeating: 0x44, count: 32)
#expect(
AnnouncementPacket(
nickname: oversizedNickname,
noisePublicKey: validKey,
signingPublicKey: validKey,
directNeighbors: nil
).encode() == nil
)
#expect(
AnnouncementPacket(
nickname: "alice",
noisePublicKey: Data(repeating: 0x55, count: 256),
signingPublicKey: validKey,
directNeighbors: nil
).encode() == nil
)
#expect(
AnnouncementPacket(
nickname: "alice",
noisePublicKey: validKey,
signingPublicKey: Data(repeating: 0x66, count: 256),
directNeighbors: nil
).encode() == nil
)
let invalidNeighborPacket = AnnouncementPacket(
nickname: "alice",
noisePublicKey: validKey,
signingPublicKey: validKey,
directNeighbors: [Data([0x01, 0x02, 0x03])]
)
let encodedWithoutNeighbors = AnnouncementPacket(
nickname: "alice",
noisePublicKey: validKey,
signingPublicKey: validKey,
directNeighbors: nil
).encode()
#expect(invalidNeighborPacket.encode() == encodedWithoutNeighbors)
}
@Test
func announcementPacketDecodeRejectsMissingFieldsAndTruncation() throws {
let missingSigningKey = makeTLV(type: 0x01, value: Data("alice".utf8))
+ makeTLV(type: 0x02, value: Data(repeating: 0x11, count: 32))
#expect(AnnouncementPacket.decode(from: missingSigningKey) == nil)
let validPacket = try #require(
AnnouncementPacket(
nickname: "alice",
noisePublicKey: Data(repeating: 0x11, count: 32),
signingPublicKey: Data(repeating: 0x22, count: 32),
directNeighbors: nil
).encode()
)
#expect(AnnouncementPacket.decode(from: validPacket.dropLast()) == nil)
}
@Test
func announcementPacketDecodeIgnoresInvalidNeighborLengths() throws {
var encoded = try #require(
AnnouncementPacket(
nickname: "alice",
noisePublicKey: Data(repeating: 0x11, count: 32),
signingPublicKey: Data(repeating: 0x22, count: 32),
directNeighbors: nil
).encode()
)
encoded.append(makeTLV(type: 0x04, value: Data(repeating: 0x99, count: 7)))
let decoded = try #require(AnnouncementPacket.decode(from: encoded))
#expect(decoded.directNeighbors == nil)
}
@Test
func privateMessagePacketRejectsUnknownTypeAndTruncation() {
let unknownTLV = Data([0x7F, 0x01, 0x41])
#expect(PrivateMessagePacket.decode(from: unknownTLV) == nil)
let truncated = Data([0x00, 0x05, 0x61])
#expect(PrivateMessagePacket.decode(from: truncated) == nil)
}
private func makeTLV(type: UInt8, value: Data) -> Data {
var data = Data([type, UInt8(value.count)])
data.append(value)
return data
}
}