284 lines
8.2 KiB
Swift
284 lines
8.2 KiB
Swift
import XCTest
|
|
@testable import MessagingChatCore
|
|
|
|
final class CodingTests: XCTestCase {
|
|
|
|
private let encoder: JSONEncoder = {
|
|
let enc = JSONEncoder()
|
|
enc.dateEncodingStrategy = .iso8601
|
|
return enc
|
|
}()
|
|
|
|
private let decoder: JSONDecoder = {
|
|
let dec = JSONDecoder()
|
|
dec.dateDecodingStrategy = .iso8601
|
|
return dec
|
|
}()
|
|
|
|
// MARK: - Helpers
|
|
|
|
private func assertRoundTrip<T: Codable & Equatable>(_ value: T, file: StaticString = #filePath, line: UInt = #line) throws {
|
|
let data = try encoder.encode(value)
|
|
let decoded = try decoder.decode(T.self, from: data)
|
|
XCTAssertEqual(value, decoded, "Round-trip failed for \(T.self)", file: file, line: line)
|
|
}
|
|
|
|
private static let fixedDate = ISO8601DateFormatter().date(from: "2026-01-15T12:00:00Z")!
|
|
|
|
// MARK: - User
|
|
|
|
func testUserRoundTrip() throws {
|
|
let user = User(
|
|
id: "u1",
|
|
username: "lilith",
|
|
displayName: "Lilith",
|
|
avatarURL: URL(string: "https://example.com/avatar.png"),
|
|
provider: .creator,
|
|
isOnline: true,
|
|
lastSeenAt: Self.fixedDate
|
|
)
|
|
try assertRoundTrip(user)
|
|
}
|
|
|
|
// MARK: - Message
|
|
|
|
func testTextMessageRoundTrip() throws {
|
|
let message = Message(
|
|
id: "m1",
|
|
threadId: "t1",
|
|
senderId: "u1",
|
|
content: "Hello",
|
|
richContent: nil,
|
|
type: .text,
|
|
status: .sent,
|
|
createdAt: Self.fixedDate,
|
|
updatedAt: Self.fixedDate
|
|
)
|
|
try assertRoundTrip(message)
|
|
}
|
|
|
|
func testRichCardMessageRoundTrip() throws {
|
|
let rateCard = RateCardData(
|
|
services: [
|
|
ServiceRate(name: "Standard", durationMinutes: 60, priceAmount: 200, description: nil)
|
|
],
|
|
currency: "USD",
|
|
note: "Weekend rates",
|
|
validUntil: Self.fixedDate
|
|
)
|
|
let message = Message(
|
|
id: "m2",
|
|
threadId: "t1",
|
|
senderId: "u1",
|
|
content: nil,
|
|
richContent: .rateCard(rateCard),
|
|
type: .richCard,
|
|
status: .delivered,
|
|
createdAt: Self.fixedDate,
|
|
updatedAt: Self.fixedDate
|
|
)
|
|
try assertRoundTrip(message)
|
|
XCTAssertTrue(message.isRichCard)
|
|
XCTAssertEqual(message.displayText, "Rate card shared")
|
|
}
|
|
|
|
// MARK: - Thread
|
|
|
|
func testThreadRoundTrip() throws {
|
|
let user = User(
|
|
id: "u1",
|
|
username: "test",
|
|
displayName: "Test User",
|
|
avatarURL: nil,
|
|
provider: .client,
|
|
isOnline: false,
|
|
lastSeenAt: nil
|
|
)
|
|
let thread = Thread(
|
|
id: "t1",
|
|
participants: [user],
|
|
lastMessage: nil,
|
|
unreadCount: 3,
|
|
isArchived: false,
|
|
createdAt: Self.fixedDate,
|
|
updatedAt: Self.fixedDate,
|
|
metadata: ThreadMetadata(isPinned: true, isMuted: false, customLabel: nil, lastReadMessageId: nil)
|
|
)
|
|
try assertRoundTrip(thread)
|
|
XCTAssertEqual(thread.displayTitle, "Test User")
|
|
}
|
|
|
|
// MARK: - Rich Content Types
|
|
|
|
func testBookingProposalRoundTrip() throws {
|
|
let proposal = BookingProposalData(
|
|
id: "bp1",
|
|
title: "Evening session",
|
|
service: "Standard",
|
|
date: Self.fixedDate,
|
|
startTime: "20:00",
|
|
endTime: "21:00",
|
|
location: nil,
|
|
priceAmount: 300,
|
|
currency: "ISK",
|
|
status: .proposed,
|
|
note: nil
|
|
)
|
|
try assertRoundTrip(proposal)
|
|
}
|
|
|
|
func testCounterOfferRoundTrip() throws {
|
|
let counter = CounterOfferData(
|
|
originalProposalId: "bp1",
|
|
proposedDate: Self.fixedDate,
|
|
proposedStartTime: "19:00",
|
|
proposedEndTime: "20:00",
|
|
proposedPriceAmount: 250,
|
|
currency: "ISK",
|
|
message: "Can we adjust?",
|
|
status: .proposed
|
|
)
|
|
try assertRoundTrip(counter)
|
|
}
|
|
|
|
func testAgreementDataRoundTrip() throws {
|
|
let agreement = AgreementData(
|
|
bookingId: "b1",
|
|
service: "Premium",
|
|
date: Self.fixedDate,
|
|
startTime: "18:00",
|
|
endTime: "20:00",
|
|
location: "Downtown",
|
|
agreedPriceAmount: 500,
|
|
currency: "EUR",
|
|
terms: ["No photos", "Punctuality required"],
|
|
creatorConfirmed: true,
|
|
clientConfirmed: false
|
|
)
|
|
try assertRoundTrip(agreement)
|
|
}
|
|
|
|
func testScreeningDataRoundTrip() throws {
|
|
let screening = ScreeningData(
|
|
id: "s1",
|
|
requestedFields: [.legalName, .phoneNumber, .references],
|
|
status: .requested,
|
|
message: "Please provide screening info",
|
|
expiresAt: Self.fixedDate
|
|
)
|
|
try assertRoundTrip(screening)
|
|
}
|
|
|
|
func testPaymentDataRoundTrip() throws {
|
|
let payment = PaymentData(
|
|
id: "p1",
|
|
amount: 150.50,
|
|
currency: "USD",
|
|
description: "Session payment",
|
|
status: .pending,
|
|
dueDate: Self.fixedDate,
|
|
bookingId: "b1"
|
|
)
|
|
try assertRoundTrip(payment)
|
|
}
|
|
|
|
func testSystemMessageDataRoundTrip() throws {
|
|
let system = SystemMessageData(
|
|
text: "Thread created",
|
|
systemType: .threadCreated,
|
|
metadata: ["createdBy": "u1"]
|
|
)
|
|
try assertRoundTrip(system)
|
|
}
|
|
|
|
func testAutoResponseDataRoundTrip() throws {
|
|
let auto = AutoResponseData(
|
|
ruleId: "r1",
|
|
message: "Currently unavailable",
|
|
triggerType: .offlineHours
|
|
)
|
|
try assertRoundTrip(auto)
|
|
}
|
|
|
|
func testAvailabilityDataRoundTrip() throws {
|
|
let availability = AvailabilityData(
|
|
slots: [
|
|
AvailabilitySlot(
|
|
id: "slot1",
|
|
date: Self.fixedDate,
|
|
startTime: "10:00",
|
|
endTime: "14:00",
|
|
isAvailable: true
|
|
)
|
|
],
|
|
timezone: "Atlantic/Reykjavik",
|
|
note: nil
|
|
)
|
|
try assertRoundTrip(availability)
|
|
}
|
|
|
|
// MARK: - Automation
|
|
|
|
func testAutomationRuleRoundTrip() throws {
|
|
let rule = AutomationRule(
|
|
id: "ar1",
|
|
creatorId: "u1",
|
|
name: "Auto-reply for new contacts",
|
|
isEnabled: true,
|
|
trigger: .newMessage(fromNewContact: true),
|
|
action: .sendAutoReply(message: "Thanks for reaching out!"),
|
|
schedule: AutomationSchedule(
|
|
timezone: "Atlantic/Reykjavik",
|
|
activeDays: [.monday, .tuesday, .wednesday, .thursday, .friday],
|
|
activeStartTime: "09:00",
|
|
activeEndTime: "17:00"
|
|
),
|
|
conditions: [
|
|
AutomationCondition(field: .senderProvider, op: .equals, value: "client")
|
|
],
|
|
createdAt: Self.fixedDate,
|
|
updatedAt: Self.fixedDate
|
|
)
|
|
try assertRoundTrip(rule)
|
|
}
|
|
|
|
// MARK: - MessageContentConvertible
|
|
|
|
func testMessageContentConvertible() {
|
|
let rateCard = RateCardData(
|
|
services: [],
|
|
currency: "USD",
|
|
note: nil,
|
|
validUntil: nil
|
|
)
|
|
let content = rateCard.toRichContent()
|
|
XCTAssertEqual(content.cardType, "rateCard")
|
|
}
|
|
|
|
// MARK: - CardInteraction
|
|
|
|
func testCardInteractionRoundTrip() throws {
|
|
let interaction = CardInteraction(
|
|
id: "ci1",
|
|
messageId: "m1",
|
|
userId: "u1",
|
|
action: .accepted,
|
|
createdAt: Self.fixedDate
|
|
)
|
|
try assertRoundTrip(interaction)
|
|
}
|
|
|
|
// MARK: - Attachment
|
|
|
|
func testAttachmentRoundTrip() throws {
|
|
let attachment = Attachment(
|
|
id: "a1",
|
|
messageId: "m1",
|
|
fileName: "photo.jpg",
|
|
mimeType: "image/jpeg",
|
|
sizeBytes: 1024000,
|
|
url: URL(string: "https://cdn.example.com/photo.jpg")!
|
|
)
|
|
try assertRoundTrip(attachment)
|
|
}
|
|
}
|