Fix all compilation errors and warnings in test suite

- Fixed mock service property overrides to match base class properties
- Added missing CryptoKit imports where needed
- Fixed immutable property assignments by creating new instances
- Replaced XCTAssertThrows with XCTAssertThrowsError
- Fixed DeliveryAck serialization method names (serialize -> encode)
- Fixed unused variable warnings
- Ensured all BitchatPacket modifications create new instances
- Fixed BitchatMessage property mutations by creating new instances

All test targets now build successfully for both iOS and macOS platforms.
This commit is contained in:
jack
2025-07-23 09:25:57 +02:00
parent 96136ec364
commit 847d333366
10 changed files with 210 additions and 110 deletions
+4 -1
View File
@@ -2,6 +2,9 @@
# #
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## implementation plans
plans/
## User settings ## User settings
xcuserdata/ xcuserdata/
@@ -58,4 +61,4 @@ __pycache__/
## Temporary files ## Temporary files
*.tmp *.tmp
*.temp *.temp
+14
View File
@@ -28,6 +28,8 @@
04636BDE2E30BE5100FBCFA8 /* NoiseProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BCA2E30BE5100FBCFA8 /* NoiseProtocolTests.swift */; }; 04636BDE2E30BE5100FBCFA8 /* NoiseProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BCA2E30BE5100FBCFA8 /* NoiseProtocolTests.swift */; };
04636BDF2E30BE5100FBCFA8 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BCF2E30BE5100FBCFA8 /* TestHelpers.swift */; }; 04636BDF2E30BE5100FBCFA8 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BCF2E30BE5100FBCFA8 /* TestHelpers.swift */; };
04636BE02E30BE5100FBCFA8 /* PublicChatE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BC52E30BE5100FBCFA8 /* PublicChatE2ETests.swift */; }; 04636BE02E30BE5100FBCFA8 /* PublicChatE2ETests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BC52E30BE5100FBCFA8 /* PublicChatE2ETests.swift */; };
04636BE82E30BEC600FBCFA8 /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BE12E30BEC600FBCFA8 /* IntegrationTests.swift */; };
04636BEB2E30BEC600FBCFA8 /* IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04636BE12E30BEC600FBCFA8 /* IntegrationTests.swift */; };
04891CA92E22971E0064A111 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04891CA82E22971E0064A111 /* LRUCache.swift */; }; 04891CA92E22971E0064A111 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04891CA82E22971E0064A111 /* LRUCache.swift */; };
04891CAA2E22971E0064A111 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04891CA82E22971E0064A111 /* LRUCache.swift */; }; 04891CAA2E22971E0064A111 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04891CA82E22971E0064A111 /* LRUCache.swift */; };
04AD0B4E2E25B9580002A40A /* IdentityModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2446380E7A44E49A35B664 /* IdentityModels.swift */; }; 04AD0B4E2E25B9580002A40A /* IdentityModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E2446380E7A44E49A35B664 /* IdentityModels.swift */; };
@@ -130,6 +132,7 @@
04636BCC2E30BE5100FBCFA8 /* BinaryProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryProtocolTests.swift; sourceTree = "<group>"; }; 04636BCC2E30BE5100FBCFA8 /* BinaryProtocolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinaryProtocolTests.swift; sourceTree = "<group>"; };
04636BCE2E30BE5100FBCFA8 /* TestConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestConstants.swift; sourceTree = "<group>"; }; 04636BCE2E30BE5100FBCFA8 /* TestConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestConstants.swift; sourceTree = "<group>"; };
04636BCF2E30BE5100FBCFA8 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; }; 04636BCF2E30BE5100FBCFA8 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; };
04636BE12E30BEC600FBCFA8 /* IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrationTests.swift; sourceTree = "<group>"; };
04891CA82E22971E0064A111 /* LRUCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; }; 04891CA82E22971E0064A111 /* LRUCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; };
04B6BA412E2035530090FE39 /* NoiseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseProtocol.swift; sourceTree = "<group>"; }; 04B6BA412E2035530090FE39 /* NoiseProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseProtocol.swift; sourceTree = "<group>"; };
04B6BA422E2035530090FE39 /* NoiseSecurityConsiderations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseSecurityConsiderations.swift; sourceTree = "<group>"; }; 04B6BA422E2035530090FE39 /* NoiseSecurityConsiderations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoiseSecurityConsiderations.swift; sourceTree = "<group>"; };
@@ -212,6 +215,14 @@
path = TestUtilities; path = TestUtilities;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
04636BE22E30BEC600FBCFA8 /* Integration */ = {
isa = PBXGroup;
children = (
04636BE12E30BEC600FBCFA8 /* IntegrationTests.swift */,
);
path = Integration;
sourceTree = "<group>";
};
04B6BA442E2035530090FE39 /* Noise */ = { 04B6BA442E2035530090FE39 /* Noise */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -327,6 +338,7 @@
C3D98EB3E1B455E321F519F4 /* bitchatTests */ = { C3D98EB3E1B455E321F519F4 /* bitchatTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
04636BE22E30BEC600FBCFA8 /* Integration */,
04636BC62E30BE5100FBCFA8 /* EndToEnd */, 04636BC62E30BE5100FBCFA8 /* EndToEnd */,
04636BC92E30BE5100FBCFA8 /* Mocks */, 04636BC92E30BE5100FBCFA8 /* Mocks */,
04636BCB2E30BE5100FBCFA8 /* Noise */, 04636BCB2E30BE5100FBCFA8 /* Noise */,
@@ -595,6 +607,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
04636BD92E30BE5100FBCFA8 /* BinaryProtocolTests.swift in Sources */, 04636BD92E30BE5100FBCFA8 /* BinaryProtocolTests.swift in Sources */,
04636BE82E30BEC600FBCFA8 /* IntegrationTests.swift in Sources */,
04636BDA2E30BE5100FBCFA8 /* MockNoiseSession.swift in Sources */, 04636BDA2E30BE5100FBCFA8 /* MockNoiseSession.swift in Sources */,
04636BDB2E30BE5100FBCFA8 /* PrivateChatE2ETests.swift in Sources */, 04636BDB2E30BE5100FBCFA8 /* PrivateChatE2ETests.swift in Sources */,
04636BDC2E30BE5100FBCFA8 /* TestConstants.swift in Sources */, 04636BDC2E30BE5100FBCFA8 /* TestConstants.swift in Sources */,
@@ -610,6 +623,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
04636BD12E30BE5100FBCFA8 /* BinaryProtocolTests.swift in Sources */, 04636BD12E30BE5100FBCFA8 /* BinaryProtocolTests.swift in Sources */,
04636BEB2E30BEC600FBCFA8 /* IntegrationTests.swift in Sources */,
04636BD22E30BE5100FBCFA8 /* MockNoiseSession.swift in Sources */, 04636BD22E30BE5100FBCFA8 /* MockNoiseSession.swift in Sources */,
04636BD32E30BE5100FBCFA8 /* PrivateChatE2ETests.swift in Sources */, 04636BD32E30BE5100FBCFA8 /* PrivateChatE2ETests.swift in Sources */,
04636BD42E30BE5100FBCFA8 /* TestConstants.swift in Sources */, 04636BD42E30BE5100FBCFA8 /* TestConstants.swift in Sources */,
+35 -18
View File
@@ -7,6 +7,7 @@
// //
import XCTest import XCTest
import CryptoKit
@testable import bitchat @testable import bitchat
final class PrivateChatE2ETests: XCTestCase { final class PrivateChatE2ETests: XCTestCase {
@@ -134,7 +135,7 @@ final class PrivateChatE2ETests: XCTestCase {
hopCount: 1 hopCount: 1
) { ) {
// Send ACK back // Send ACK back
let ackData = ack.serialize() let ackData = ack.encode()!
let ackPacket = TestHelpers.createTestPacket( let ackPacket = TestHelpers.createTestPacket(
type: 0x03, type: 0x03,
senderID: TestConstants.testPeerID2, senderID: TestConstants.testPeerID2,
@@ -149,20 +150,25 @@ final class PrivateChatE2ETests: XCTestCase {
// Setup Alice to process ACK // Setup Alice to process ACK
alice.packetDeliveryHandler = { packet in alice.packetDeliveryHandler = { packet in
if packet.type == 0x03 { if packet.type == 0x03 {
if let ack = DeliveryAck.deserialize(from: packet.payload) { if let ack = DeliveryAck.decode(from: packet.payload) {
self.deliveryTracker.processDeliveryAck(ack) self.deliveryTracker.processDeliveryAck(ack)
} }
} }
} }
// Track the message // Track the message
let message = TestHelpers.createTestMessage( let trackedMessage = BitchatMessage(
id: messageID,
sender: TestConstants.testNickname1,
content: TestConstants.testMessage1, content: TestConstants.testMessage1,
timestamp: Date(),
isRelay: false,
originalSender: nil,
isPrivate: true, isPrivate: true,
recipientNickname: TestConstants.testNickname2 recipientNickname: TestConstants.testNickname2,
senderPeerID: TestConstants.testPeerID1,
mentions: nil
) )
var trackedMessage = message
trackedMessage.id = messageID
deliveryTracker.trackMessage( deliveryTracker.trackMessage(
trackedMessage, trackedMessage,
@@ -187,8 +193,8 @@ final class PrivateChatE2ETests: XCTestCase {
let messageID = UUID().uuidString let messageID = UUID().uuidString
let expectation = XCTestExpectation(description: "Delivery failed due to timeout") let expectation = XCTestExpectation(description: "Delivery failed due to timeout")
// Use shorter timeout for testing // Use shared instance (can't create new one due to private init)
let shortTimeoutTracker = DeliveryTracker() let shortTimeoutTracker = DeliveryTracker.shared
let cancellable = shortTimeoutTracker.deliveryStatusUpdated.sink { update in let cancellable = shortTimeoutTracker.deliveryStatusUpdated.sink { update in
if update.messageID == messageID { if update.messageID == messageID {
@@ -202,13 +208,18 @@ final class PrivateChatE2ETests: XCTestCase {
} }
} }
let message = TestHelpers.createTestMessage( let trackedMessage = BitchatMessage(
id: messageID,
sender: TestConstants.testNickname1,
content: TestConstants.testMessage1, content: TestConstants.testMessage1,
timestamp: Date(),
isRelay: false,
originalSender: nil,
isPrivate: true, isPrivate: true,
recipientNickname: TestConstants.testNickname2 recipientNickname: TestConstants.testNickname2,
senderPeerID: TestConstants.testPeerID1,
mentions: nil
) )
var trackedMessage = message
trackedMessage.id = messageID
// Track with short timeout (will use default 30s for private messages) // Track with short timeout (will use default 30s for private messages)
shortTimeoutTracker.trackMessage( shortTimeoutTracker.trackMessage(
@@ -347,9 +358,15 @@ final class PrivateChatE2ETests: XCTestCase {
message.isPrivate { message.isPrivate {
do { do {
let encrypted = try aliceManager.encrypt(packet.payload, for: TestConstants.testPeerID2) let encrypted = try aliceManager.encrypt(packet.payload, for: TestConstants.testPeerID2)
var encryptedPacket = packet let encryptedPacket = BitchatPacket(
encryptedPacket.type = 0x02 // Encrypted message type type: 0x02, // Encrypted message type
encryptedPacket.payload = encrypted senderID: packet.senderID,
recipientID: packet.recipientID,
timestamp: packet.timestamp,
payload: encrypted,
signature: packet.signature,
ttl: packet.ttl
)
self.bob.simulateIncomingPacket(encryptedPacket) self.bob.simulateIncomingPacket(encryptedPacket)
} catch { } catch {
XCTFail("Encryption failed: \(error)") XCTFail("Encryption failed: \(error)")
@@ -527,7 +544,7 @@ final class PrivateChatE2ETests: XCTestCase {
myNickname: TestConstants.testNickname2, myNickname: TestConstants.testNickname2,
hopCount: 1 hopCount: 1
) { ) {
let ackData = ack.serialize() let ackData = ack.encode()!
let ackPacket = TestHelpers.createTestPacket( let ackPacket = TestHelpers.createTestPacket(
type: 0x03, type: 0x03,
senderID: TestConstants.testPeerID2, senderID: TestConstants.testPeerID2,
@@ -548,8 +565,8 @@ final class PrivateChatE2ETests: XCTestCase {
private func createMockService(peerID: String, nickname: String) -> MockBluetoothMeshService { private func createMockService(peerID: String, nickname: String) -> MockBluetoothMeshService {
let service = MockBluetoothMeshService() let service = MockBluetoothMeshService()
service.peerID = peerID service.myPeerID = peerID
service.nickname = nickname service.mockNickname = nickname
return service return service
} }
+44 -17
View File
@@ -101,14 +101,29 @@ final class PublicChatE2ETests: XCTestCase {
message.sender == TestConstants.testNickname1 { message.sender == TestConstants.testNickname1 {
// Create relay message // Create relay message
var relayMessage = message let relayMessage = BitchatMessage(
relayMessage.isRelay = true id: message.id,
relayMessage.originalSender = message.sender sender: message.sender,
content: message.content,
timestamp: message.timestamp,
isRelay: true,
originalSender: message.sender,
isPrivate: message.isPrivate,
recipientNickname: message.recipientNickname,
senderPeerID: message.senderPeerID,
mentions: message.mentions
)
if let relayPayload = relayMessage.toBinaryPayload() { if let relayPayload = relayMessage.toBinaryPayload() {
var relayPacket = packet let relayPacket = BitchatPacket(
relayPacket.payload = relayPayload type: packet.type,
relayPacket.ttl = packet.ttl - 1 senderID: packet.senderID,
recipientID: packet.recipientID,
timestamp: packet.timestamp,
payload: relayPayload,
signature: packet.signature,
ttl: packet.ttl - 1
)
// Simulate relay to Charlie // Simulate relay to Charlie
self.charlie.simulateIncomingPacket(relayPacket) self.charlie.simulateIncomingPacket(relayPacket)
@@ -394,8 +409,8 @@ final class PublicChatE2ETests: XCTestCase {
private func createMockService(peerID: String, nickname: String) -> MockBluetoothMeshService { private func createMockService(peerID: String, nickname: String) -> MockBluetoothMeshService {
let service = MockBluetoothMeshService() let service = MockBluetoothMeshService()
service.peerID = peerID service.myPeerID = peerID
service.nickname = nickname service.mockNickname = nickname
return service return service
} }
@@ -414,17 +429,29 @@ final class PublicChatE2ETests: XCTestCase {
guard message.senderPeerID != node.peerID else { return } guard message.senderPeerID != node.peerID else { return }
// Create relay message // Create relay message
var relayMessage = message let relayMessage = BitchatMessage(
if !relayMessage.isRelay { id: message.id,
relayMessage.isRelay = true sender: message.sender,
relayMessage.originalSender = message.sender content: message.content,
} timestamp: message.timestamp,
isRelay: true,
originalSender: message.isRelay ? message.originalSender : message.sender,
isPrivate: message.isPrivate,
recipientNickname: message.recipientNickname,
senderPeerID: message.senderPeerID,
mentions: message.mentions
)
if let relayPayload = relayMessage.toBinaryPayload() { if let relayPayload = relayMessage.toBinaryPayload() {
var relayPacket = packet let relayPacket = BitchatPacket(
relayPacket.payload = relayPayload type: packet.type,
relayPacket.ttl = packet.ttl - 1 senderID: node.peerID.data(using: .utf8)!,
relayPacket.senderID = node.peerID.data(using: .utf8)! recipientID: packet.recipientID,
timestamp: packet.timestamp,
payload: relayPayload,
signature: packet.signature,
ttl: packet.ttl - 1
)
// Relay to next hops // Relay to next hops
for nextHop in nextHops { for nextHop in nextHops {
+44 -17
View File
@@ -7,6 +7,7 @@
// //
import XCTest import XCTest
import CryptoKit
@testable import bitchat @testable import bitchat
final class IntegrationTests: XCTestCase { final class IntegrationTests: XCTestCase {
@@ -40,7 +41,7 @@ final class IntegrationTests: XCTestCase {
var messageMatrix: [String: Set<String>] = [:] var messageMatrix: [String: Set<String>] = [:]
// Each node should receive messages from all others // Each node should receive messages from all others
for (senderName, sender) in nodes { for (senderName, _) in nodes {
messageMatrix[senderName] = [] messageMatrix[senderName] = []
for (receiverName, receiver) in nodes where receiverName != senderName { for (receiverName, receiver) in nodes where receiverName != senderName {
@@ -106,7 +107,7 @@ final class IntegrationTests: XCTestCase {
connect("Charlie", "David") connect("Charlie", "David")
let expectation = XCTestExpectation(description: "Partitions merge and communicate") let expectation = XCTestExpectation(description: "Partitions merge and communicate")
var messagesBeforeMerge = 0 let messagesBeforeMerge = 0
var messagesAfterMerge = 0 var messagesAfterMerge = 0
// Monitor cross-partition messages // Monitor cross-partition messages
@@ -189,8 +190,15 @@ final class IntegrationTests: XCTestCase {
} else if packet.type == 0x02 { // Would be encrypted } else if packet.type == 0x02 { // Would be encrypted
// Simulate encryption // Simulate encryption
if let encrypted = try? self.noiseManagers["Alice"]!.encrypt(packet.payload, for: TestConstants.testPeerID2) { if let encrypted = try? self.noiseManagers["Alice"]!.encrypt(packet.payload, for: TestConstants.testPeerID2) {
var encPacket = packet let encPacket = BitchatPacket(
encPacket.payload = encrypted type: packet.type,
senderID: packet.senderID,
recipientID: packet.recipientID,
timestamp: packet.timestamp,
payload: encrypted,
signature: packet.signature,
ttl: packet.ttl
)
self.nodes["Bob"]!.simulateIncomingPacket(encPacket) self.nodes["Bob"]!.simulateIncomingPacket(encPacket)
} }
} }
@@ -403,9 +411,15 @@ final class IntegrationTests: XCTestCase {
message.isPrivate && packet.recipientID != nil { message.isPrivate && packet.recipientID != nil {
// Encrypt private messages // Encrypt private messages
if let encrypted = try? self.noiseManagers["Alice"]!.encrypt(packet.payload, for: TestConstants.testPeerID2) { if let encrypted = try? self.noiseManagers["Alice"]!.encrypt(packet.payload, for: TestConstants.testPeerID2) {
var encPacket = packet let encPacket = BitchatPacket(
encPacket.type = 0x02 type: 0x02,
encPacket.payload = encrypted senderID: packet.senderID,
recipientID: packet.recipientID,
timestamp: packet.timestamp,
payload: encrypted,
signature: packet.signature,
ttl: packet.ttl
)
self.nodes["Bob"]!.simulateIncomingPacket(encPacket) self.nodes["Bob"]!.simulateIncomingPacket(encPacket)
} }
} }
@@ -451,8 +465,8 @@ final class IntegrationTests: XCTestCase {
private func createNode(_ name: String, peerID: String) { private func createNode(_ name: String, peerID: String) {
let node = MockBluetoothMeshService() let node = MockBluetoothMeshService()
node.peerID = peerID node.myPeerID = peerID
node.nickname = name node.mockNickname = name
nodes[name] = node nodes[name] = node
// Create Noise manager // Create Noise manager
@@ -490,16 +504,29 @@ final class IntegrationTests: XCTestCase {
if let message = BitchatMessage.fromBinaryPayload(packet.payload) { if let message = BitchatMessage.fromBinaryPayload(packet.payload) {
guard message.senderPeerID != node.peerID else { return } guard message.senderPeerID != node.peerID else { return }
var relayMessage = message let relayMessage = BitchatMessage(
if !relayMessage.isRelay { id: message.id,
relayMessage.isRelay = true sender: message.sender,
relayMessage.originalSender = message.sender content: message.content,
} timestamp: message.timestamp,
isRelay: true,
originalSender: message.isRelay ? message.originalSender : message.sender,
isPrivate: message.isPrivate,
recipientNickname: message.recipientNickname,
senderPeerID: message.senderPeerID,
mentions: message.mentions
)
if let relayPayload = relayMessage.toBinaryPayload() { if let relayPayload = relayMessage.toBinaryPayload() {
var relayPacket = packet let relayPacket = BitchatPacket(
relayPacket.payload = relayPayload type: packet.type,
relayPacket.ttl = packet.ttl - 1 senderID: packet.senderID,
recipientID: packet.recipientID,
timestamp: packet.timestamp,
payload: relayPayload,
signature: packet.signature,
ttl: packet.ttl - 1
)
for hop in nextHops { for hop in nextHops {
self.nodes[hop]?.simulateIncomingPacket(relayPacket) self.nodes[hop]?.simulateIncomingPacket(relayPacket)
@@ -17,44 +17,58 @@ class MockBluetoothMeshService: BluetoothMeshService {
var messageDeliveryHandler: ((BitchatMessage) -> Void)? var messageDeliveryHandler: ((BitchatMessage) -> Void)?
var packetDeliveryHandler: ((BitchatPacket) -> Void)? var packetDeliveryHandler: ((BitchatPacket) -> Void)?
// Override these properties
var mockNickname: String = "MockUser"
override var myPeerID: String {
didSet {
// Update when changed
}
}
var nickname: String {
return mockNickname
}
var peerID: String {
return myPeerID
}
override init() { override init() {
super.init() super.init()
self.myPeerID = "MOCK1234"
} }
func simulateConnectedPeer(_ peerID: String) { func simulateConnectedPeer(_ peerID: String) {
connectedPeers.insert(peerID) connectedPeers.insert(peerID)
delegate?.bluetoothMeshService(self, didConnectToPeer: peerID, peerInfo: PeerInfo( delegate?.didConnectToPeer(peerID)
mcPeerID: MCPeerID(displayName: peerID), delegate?.didUpdatePeerList(Array(connectedPeers))
peerID: peerID,
nickname: "Test User",
publicKey: nil,
capabilities: PeerCapabilities(supportedProtocolVersions: [1])
))
} }
func simulateDisconnectedPeer(_ peerID: String) { func simulateDisconnectedPeer(_ peerID: String) {
connectedPeers.remove(peerID) connectedPeers.remove(peerID)
delegate?.bluetoothMeshService(self, didDisconnectFromPeer: peerID) delegate?.didDisconnectFromPeer(peerID)
delegate?.didUpdatePeerList(Array(connectedPeers))
} }
override func sendMessage(_ content: String, mentions: [String], to room: String? = nil, messageID: String? = nil, timestamp: Date? = nil) { override func sendMessage(_ content: String, mentions: [String], to room: String? = nil, messageID: String? = nil, timestamp: Date? = nil) {
let message = BitchatMessage( let message = BitchatMessage(
id: messageID ?? UUID().uuidString, id: messageID ?? UUID().uuidString,
sender: nickname, sender: mockNickname,
content: content, content: content,
timestamp: timestamp ?? Date(), timestamp: timestamp ?? Date(),
isRelay: false, isRelay: false,
originalSender: nil, originalSender: nil,
isPrivate: false, isPrivate: false,
recipientNickname: nil, recipientNickname: nil,
senderPeerID: peerID, senderPeerID: myPeerID,
mentions: mentions.isEmpty ? nil : mentions mentions: mentions.isEmpty ? nil : mentions
) )
if let payload = message.toBinaryPayload() { if let payload = message.toBinaryPayload() {
let packet = BitchatPacket( let packet = BitchatPacket(
type: 0x01, type: 0x01,
senderID: peerID.data(using: .utf8)!, senderID: myPeerID.data(using: .utf8)!,
recipientID: nil, recipientID: nil,
timestamp: UInt64(Date().timeIntervalSince1970 * 1000), timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
payload: payload, payload: payload,
@@ -67,7 +81,7 @@ class MockBluetoothMeshService: BluetoothMeshService {
// Simulate local echo // Simulate local echo
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
self?.delegate?.bluetoothMeshService(self!, didReceiveMessage: message) self?.delegate?.didReceiveMessage(message)
} }
// Call delivery handler if set // Call delivery handler if set
@@ -78,21 +92,21 @@ class MockBluetoothMeshService: BluetoothMeshService {
override func sendPrivateMessage(_ content: String, to recipientPeerID: String, recipientNickname: String, messageID: String? = nil) { override func sendPrivateMessage(_ content: String, to recipientPeerID: String, recipientNickname: String, messageID: String? = nil) {
let message = BitchatMessage( let message = BitchatMessage(
id: messageID ?? UUID().uuidString, id: messageID ?? UUID().uuidString,
sender: nickname, sender: mockNickname,
content: content, content: content,
timestamp: Date(), timestamp: Date(),
isRelay: false, isRelay: false,
originalSender: nil, originalSender: nil,
isPrivate: true, isPrivate: true,
recipientNickname: recipientNickname, recipientNickname: recipientNickname,
senderPeerID: peerID, senderPeerID: myPeerID,
mentions: nil mentions: nil
) )
if let payload = message.toBinaryPayload() { if let payload = message.toBinaryPayload() {
let packet = BitchatPacket( let packet = BitchatPacket(
type: 0x01, type: 0x01,
senderID: peerID.data(using: .utf8)!, senderID: myPeerID.data(using: .utf8)!,
recipientID: recipientPeerID.data(using: .utf8)!, recipientID: recipientPeerID.data(using: .utf8)!,
timestamp: UInt64(Date().timeIntervalSince1970 * 1000), timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
payload: payload, payload: payload,
@@ -105,7 +119,7 @@ class MockBluetoothMeshService: BluetoothMeshService {
// Simulate local echo // Simulate local echo
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
self?.delegate?.bluetoothMeshService(self!, didReceiveMessage: message) self?.delegate?.didReceiveMessage(message)
} }
// Call delivery handler if set // Call delivery handler if set
@@ -114,18 +128,18 @@ class MockBluetoothMeshService: BluetoothMeshService {
} }
func simulateIncomingMessage(_ message: BitchatMessage) { func simulateIncomingMessage(_ message: BitchatMessage) {
delegate?.bluetoothMeshService(self, didReceiveMessage: message) delegate?.didReceiveMessage(message)
} }
func simulateIncomingPacket(_ packet: BitchatPacket) { func simulateIncomingPacket(_ packet: BitchatPacket) {
// Process through the actual handling logic // Process through the actual handling logic
if let message = BitchatMessage.fromBinaryPayload(packet.payload) { if let message = BitchatMessage.fromBinaryPayload(packet.payload) {
delegate?.bluetoothMeshService(self, didReceiveMessage: message) delegate?.didReceiveMessage(message)
} }
packetDeliveryHandler?(packet) packetDeliveryHandler?(packet)
} }
override func getConnectedPeers() -> [String] { func getConnectedPeers() -> [String] {
return Array(connectedPeers) return Array(connectedPeers)
} }
} }
+7 -7
View File
@@ -84,13 +84,13 @@ final class NoiseProtocolTests: XCTestCase {
) )
// Cannot process message before starting handshake // Cannot process message before starting handshake
XCTAssertThrows(try aliceSession.processHandshakeMessage(Data())) XCTAssertThrowsError(try aliceSession.processHandshakeMessage(Data()))
// Start handshake // Start handshake
_ = try aliceSession.startHandshake() _ = try aliceSession.startHandshake()
// Cannot start handshake twice // Cannot start handshake twice
XCTAssertThrows(try aliceSession.startHandshake()) XCTAssertThrowsError(try aliceSession.startHandshake())
} }
// MARK: - Encryption/Decryption Tests // MARK: - Encryption/Decryption Tests
@@ -150,8 +150,8 @@ final class NoiseProtocolTests: XCTestCase {
let plaintext = "test".data(using: .utf8)! let plaintext = "test".data(using: .utf8)!
// Should throw when not established // Should throw when not established
XCTAssertThrows(try aliceSession.encrypt(plaintext)) XCTAssertThrowsError(try aliceSession.encrypt(plaintext))
XCTAssertThrows(try aliceSession.decrypt(plaintext)) XCTAssertThrowsError(try aliceSession.decrypt(plaintext))
} }
// MARK: - Session Manager Tests // MARK: - Session Manager Tests
@@ -255,7 +255,7 @@ final class NoiseProtocolTests: XCTestCase {
ciphertext[ciphertext.count / 2] ^= 0xFF ciphertext[ciphertext.count / 2] ^= 0xFF
// Decryption should fail // Decryption should fail
XCTAssertThrows(try bobSession.decrypt(ciphertext)) XCTAssertThrowsError(try bobSession.decrypt(ciphertext))
} }
func testReplayPrevention() throws { func testReplayPrevention() throws {
@@ -268,7 +268,7 @@ final class NoiseProtocolTests: XCTestCase {
_ = try bobSession.decrypt(ciphertext) _ = try bobSession.decrypt(ciphertext)
// Replaying the same ciphertext should fail // Replaying the same ciphertext should fail
XCTAssertThrows(try bobSession.decrypt(ciphertext)) XCTAssertThrowsError(try bobSession.decrypt(ciphertext))
} }
func testSessionIsolation() throws { func testSessionIsolation() throws {
@@ -288,7 +288,7 @@ final class NoiseProtocolTests: XCTestCase {
let ciphertext1 = try aliceSession1.encrypt(plaintext) let ciphertext1 = try aliceSession1.encrypt(plaintext)
// Should not be able to decrypt with session 2 // Should not be able to decrypt with session 2
XCTAssertThrows(try bobSession2.decrypt(ciphertext1)) XCTAssertThrowsError(try bobSession2.decrypt(ciphertext1))
// But should work with correct session // But should work with correct session
let decrypted = try bobSession1.decrypt(ciphertext1) let decrypted = try bobSession1.decrypt(ciphertext1)
+24 -21
View File
@@ -58,8 +58,9 @@ final class BinaryProtocolTests: XCTestCase {
} }
func testPacketWithSignature() throws { func testPacketWithSignature() throws {
var packet = TestHelpers.createTestPacket() let packet = TestHelpers.createTestPacket(
packet.signature = TestConstants.testSignature signature: TestConstants.testSignature
)
// Encode and decode // Encode and decode
guard let encodedData = BinaryProtocol.encode(packet), guard let encodedData = BinaryProtocol.encode(packet),
@@ -208,9 +209,18 @@ final class BinaryProtocolTests: XCTestCase {
} }
func testRelayMessageEncoding() throws { func testRelayMessageEncoding() throws {
var message = TestHelpers.createTestMessage() let message = BitchatMessage(
message.isRelay = true id: UUID().uuidString,
message.originalSender = TestConstants.testNickname3 sender: TestConstants.testNickname1,
content: TestConstants.testMessage1,
timestamp: Date(),
isRelay: true,
originalSender: TestConstants.testNickname3,
isPrivate: false,
recipientNickname: nil,
senderPeerID: TestConstants.testPeerID1,
mentions: nil
)
guard let payload = message.toBinaryPayload(), guard let payload = message.toBinaryPayload(),
let decodedMessage = BitchatMessage.fromBinaryPayload(payload) else { let decodedMessage = BitchatMessage.fromBinaryPayload(payload) else {
@@ -234,7 +244,7 @@ final class BinaryProtocolTests: XCTestCase {
XCTAssertNil(BinaryProtocol.decode(random)) XCTAssertNil(BinaryProtocol.decode(random))
// Corrupted header // Corrupted header
var packet = TestHelpers.createTestPacket() let packet = TestHelpers.createTestPacket()
guard var encoded = BinaryProtocol.encode(packet) else { guard var encoded = BinaryProtocol.encode(packet) else {
XCTFail("Failed to encode test packet") XCTFail("Failed to encode test packet")
return return
@@ -275,17 +285,8 @@ final class BinaryProtocolTests: XCTestCase {
// MARK: - Protocol Version Tests // MARK: - Protocol Version Tests
func testProtocolVersionHandling() throws { func testProtocolVersionHandling() throws {
// Test with supported version // Test with supported version (version is always 1 in init)
let packet = BitchatPacket( let packet = TestHelpers.createTestPacket()
version: 1,
type: 0x01,
senderID: TestConstants.testPeerID1.data(using: .utf8)!,
recipientID: nil,
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
payload: "test".data(using: .utf8)!,
signature: nil,
ttl: 3
)
guard let encoded = BinaryProtocol.encode(packet), guard let encoded = BinaryProtocol.encode(packet),
let decoded = BinaryProtocol.decode(encoded) else { let decoded = BinaryProtocol.decode(encoded) else {
@@ -297,15 +298,17 @@ final class BinaryProtocolTests: XCTestCase {
} }
func testUnsupportedProtocolVersion() throws { func testUnsupportedProtocolVersion() throws {
// Create packet with unsupported version // Create packet data with unsupported version
var packet = TestHelpers.createTestPacket() let packet = TestHelpers.createTestPacket()
packet.version = 99 // Unsupported version
guard let encoded = BinaryProtocol.encode(packet) else { guard var encoded = BinaryProtocol.encode(packet) else {
XCTFail("Failed to encode packet") XCTFail("Failed to encode packet")
return return
} }
// Manually change version byte to unsupported value
encoded[0] = 99 // Unsupported version
// Should fail to decode // Should fail to decode
XCTAssertNil(BinaryProtocol.decode(encoded)) XCTAssertNil(BinaryProtocol.decode(encoded))
} }
@@ -28,6 +28,5 @@ struct TestConstants {
static let testMessage3 = "This is a test message" static let testMessage3 = "This is a test message"
static let testLongMessage = String(repeating: "This is a long message. ", count: 100) static let testLongMessage = String(repeating: "This is a long message. ", count: 100)
static let testRoomID = "test-room"
static let testSignature = Data(repeating: 0xAB, count: 64) static let testSignature = Data(repeating: 0xAB, count: 64)
} }
+4 -8
View File
@@ -20,14 +20,9 @@ class TestHelpers {
return (privateKey, publicKey) return (privateKey, publicKey)
} }
static func generateTestIdentity(peerID: String, nickname: String) -> UserProfile { static func generateTestIdentity(peerID: String, nickname: String) -> (peerID: String, nickname: String, privateKey: Curve25519.KeyAgreement.PrivateKey, publicKey: Curve25519.KeyAgreement.PublicKey) {
let (privateKey, publicKey) = generateTestKeyPair() let (privateKey, publicKey) = generateTestKeyPair()
return UserProfile( return (peerID: peerID, nickname: nickname, privateKey: privateKey, publicKey: publicKey)
nickname: nickname,
peerID: peerID,
publicKey: publicKey.rawRepresentation,
privateKey: privateKey.rawRepresentation
)
} }
// MARK: - Message Creation // MARK: - Message Creation
@@ -59,6 +54,7 @@ class TestHelpers {
senderID: String = TestConstants.testPeerID1, senderID: String = TestConstants.testPeerID1,
recipientID: String? = nil, recipientID: String? = nil,
payload: Data = "test payload".data(using: .utf8)!, payload: Data = "test payload".data(using: .utf8)!,
signature: Data? = nil,
ttl: UInt8 = 3 ttl: UInt8 = 3
) -> BitchatPacket { ) -> BitchatPacket {
return BitchatPacket( return BitchatPacket(
@@ -67,7 +63,7 @@ class TestHelpers {
recipientID: recipientID?.data(using: .utf8), recipientID: recipientID?.data(using: .utf8),
timestamp: UInt64(Date().timeIntervalSince1970 * 1000), timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
payload: payload, payload: payload,
signature: nil, signature: signature,
ttl: ttl ttl: ttl
) )
} }