import XCTest @testable import Rosetta @MainActor final class BehaviorParityFixtureTests: XCTestCase { private var ctx: DBTestContext! override func setUpWithError() throws { ctx = DBTestContext() } override func tearDownWithError() throws { ctx.teardown() ctx = nil } func testIncomingDirectFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "incoming direct", events: [ .incoming(opponent: "02peer_direct", messageId: "in-1", timestamp: 100, text: "hello"), ])) let snapshot = try ctx.normalizedSnapshot() XCTAssertEqual(snapshot.messages.count, 1) XCTAssertEqual(snapshot.messages.first?.messageId, "in-1") XCTAssertEqual(snapshot.messages.first?.delivered, DeliveryStatus.delivered.rawValue) XCTAssertEqual(snapshot.messages.first?.read, false) XCTAssertEqual(snapshot.dialogs.count, 1) XCTAssertEqual(snapshot.dialogs.first?.opponentKey, "02peer_direct") XCTAssertEqual(snapshot.dialogs.first?.unreadCount, 1) XCTAssertEqual(snapshot.dialogs.first?.iHaveSent, false) XCTAssertEqual(snapshot.dialogs.first?.isRequest, true) } func testOutgoingDeliveredReadFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "outgoing delivered read", events: [ .outgoing(opponent: "02peer_ack", messageId: "out-1", timestamp: 200, text: "yo"), .markDelivered(opponent: "02peer_ack", messageId: "out-1"), .markOutgoingRead(opponent: "02peer_ack"), ])) let snapshot = try ctx.normalizedSnapshot() XCTAssertEqual(snapshot.messages.count, 1) XCTAssertEqual(snapshot.messages.first?.fromMe, true) XCTAssertEqual(snapshot.messages.first?.delivered, DeliveryStatus.delivered.rawValue) XCTAssertEqual(snapshot.messages.first?.read, true) XCTAssertEqual(snapshot.dialogs.first?.lastMessageFromMe, true) XCTAssertEqual(snapshot.dialogs.first?.lastMessageDelivered, DeliveryStatus.delivered.rawValue) XCTAssertEqual(snapshot.dialogs.first?.lastMessageRead, true) } func testSyncBatchDedupFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "sync dedup", events: [ .incoming(opponent: "02peer_dedup", messageId: "dup-1", timestamp: 300, text: "a"), .incoming(opponent: "02peer_dedup", messageId: "dup-1", timestamp: 300, text: "a"), ])) let snapshot = try ctx.normalizedSnapshot() XCTAssertEqual(snapshot.messages.count, 1) XCTAssertEqual(snapshot.messages.first?.messageId, "dup-1") } func testSavedMessagesFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "saved", events: [ .outgoing(opponent: ctx.account, messageId: "self-1", timestamp: 400, text: "note"), .markDelivered(opponent: ctx.account, messageId: "self-1"), ])) let snapshot = try ctx.normalizedSnapshot() XCTAssertEqual(snapshot.messages.count, 1) XCTAssertEqual(snapshot.messages.first?.dialogKey, ctx.account) XCTAssertEqual(snapshot.dialogs.first?.opponentKey, ctx.account) XCTAssertEqual(snapshot.dialogs.first?.unreadCount, 0) } func testGroupConversationDbFlowSafeFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "group safe", events: [ .incomingPacket( from: "02group_member_a", to: "#group:alpha", messageId: "g-1", timestamp: 500, text: "group hi" ), .incomingPacket( from: "02conversation_member", to: "conversation:room42", messageId: "c-1", timestamp: 501, text: "conv hi" ), ])) let snapshot = try ctx.normalizedSnapshot() let groupMessage = snapshot.messages.first { $0.messageId == "g-1" } let conversationMessage = snapshot.messages.first { $0.messageId == "c-1" } XCTAssertEqual(groupMessage?.dialogKey, "#group:alpha") XCTAssertEqual(conversationMessage?.dialogKey, "conversation:room42") let groupDialog = snapshot.dialogs.first { $0.opponentKey == "#group:alpha" } let conversationDialog = snapshot.dialogs.first { $0.opponentKey == "conversation:room42" } XCTAssertEqual(groupDialog?.iHaveSent, true) XCTAssertEqual(groupDialog?.isRequest, false) XCTAssertEqual(conversationDialog?.iHaveSent, true) XCTAssertEqual(conversationDialog?.isRequest, false) } func testAttachmentsOnlyLastMessageFixture() async throws { try await ctx.bootstrap() let imageAttachment = MessageAttachment(id: "att-1", preview: "", blob: "", type: .image) try await ctx.runScenario(FixtureScenario(name: "attachments only", events: [ .incoming(opponent: "02peer_media", messageId: "media-1", timestamp: 600, text: "", attachments: [imageAttachment]), ])) let snapshot = try ctx.normalizedSnapshot() XCTAssertEqual(snapshot.messages.first?.hasAttachments, true) XCTAssertEqual(snapshot.dialogs.first?.lastMessage, "Photo") } func testGroupReadPacketMarksOutgoingAsReadFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "group read", events: [ .outgoing(opponent: "#group:alpha", messageId: "g-out-1", timestamp: 610, text: "hello group"), .markDelivered(opponent: "#group:alpha", messageId: "g-out-1"), .applyReadPacket(from: "02group_member_b", to: "#group:alpha"), ])) let snapshot = try ctx.normalizedSnapshot() let message = snapshot.messages.first { $0.messageId == "g-out-1" } let dialog = snapshot.dialogs.first { $0.opponentKey == "#group:alpha" } XCTAssertEqual(message?.fromMe, true) XCTAssertEqual(message?.read, true) XCTAssertEqual(dialog?.lastMessageRead, true) } func testCallAttachmentDecodeAndStorageFixture() async throws { try await ctx.bootstrap() let callAttachment = MessageAttachment( id: "call-1", preview: "", blob: "", type: .call ) try await ctx.runScenario(FixtureScenario(name: "call attachment", events: [ .incomingPacket( from: "02peer_call", to: ctx.account, messageId: "call-msg-1", timestamp: 620, text: "", attachments: [callAttachment] ), ])) let snapshot = try ctx.normalizedSnapshot() XCTAssertEqual(snapshot.messages.first?.hasAttachments, true) XCTAssertEqual(snapshot.dialogs.first?.lastMessage, "Call") } func testRequestToChatPromotionAndCursorMonotonicityFixture() async throws { try await ctx.bootstrap() try await ctx.runScenario(FixtureScenario(name: "request to chat", events: [ .incoming(opponent: "02peer_promote", messageId: "rq-1", timestamp: 700, text: "ping"), .outgoing(opponent: "02peer_promote", messageId: "rq-2", timestamp: 701, text: "pong"), .saveSyncCursor(1_700_000_001_000), .saveSyncCursor(1_700_000_000_900), .saveSyncCursor(1_700_000_001_200), ])) let snapshot = try ctx.normalizedSnapshot() let dialog = snapshot.dialogs.first { $0.opponentKey == "02peer_promote" } XCTAssertEqual(dialog?.iHaveSent, true) XCTAssertEqual(dialog?.isRequest, false) XCTAssertEqual(snapshot.syncCursor, 1_700_000_001_200) } }