171 lines
6 KiB
Swift
171 lines
6 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import IMessageSync
|
|
|
|
private func makeTestMessage(
|
|
guid: String = "test-guid",
|
|
text: String? = "Hello",
|
|
attachments: [iMessageAttachment] = [],
|
|
expressiveSendStyleId: String? = nil,
|
|
associatedMessageGuid: String? = nil,
|
|
senderDisplayName: String? = nil
|
|
) -> iMessage {
|
|
iMessage(
|
|
guid: guid,
|
|
conversationId: "conv-001",
|
|
senderId: nil,
|
|
isFromMe: true,
|
|
date: Date(),
|
|
dateDelivered: nil,
|
|
dateRead: nil,
|
|
text: text,
|
|
attributedBody: nil,
|
|
associatedMessageType: nil,
|
|
associatedMessageGuid: associatedMessageGuid,
|
|
isAudioMessage: false,
|
|
expressiveSendStyleId: expressiveSendStyleId,
|
|
replyToGuid: nil,
|
|
threadOriginatorGuid: nil,
|
|
groupTitle: nil,
|
|
balloonBundleId: nil,
|
|
service: "iMessage",
|
|
senderIdentifier: nil,
|
|
senderDisplayName: senderDisplayName,
|
|
senderPhoneNumber: nil,
|
|
senderEmail: nil,
|
|
attachments: attachments,
|
|
attachmentsCount: attachments.count,
|
|
attachmentsTotalSize: attachments.reduce(0) { $0 + $1.size },
|
|
attachmentsFiletypes: Array(Set(attachments.compactMap { $0.mimeType }))
|
|
)
|
|
}
|
|
|
|
@Suite("Adaptive Chunking")
|
|
struct AdaptiveChunkingTests {
|
|
|
|
@Test func emptyMessagesProducesEmptyChunks() {
|
|
let chunks = ChunkingStrategy.createAdaptiveChunks([])
|
|
#expect(chunks.isEmpty)
|
|
}
|
|
|
|
@Test func singleSmallMessageProducesOneChunk() {
|
|
let chunks = ChunkingStrategy.createAdaptiveChunks([makeTestMessage()])
|
|
#expect(chunks.count == 1)
|
|
#expect(chunks[0].count == 1)
|
|
}
|
|
|
|
@Test func multipleSmallMessagesUnderLimitProduceSingleChunk() {
|
|
let messages = (0..<10).map { makeTestMessage(guid: "msg-\($0)") }
|
|
let chunks = ChunkingStrategy.createAdaptiveChunks(messages)
|
|
#expect(chunks.count == 1)
|
|
#expect(chunks[0].count == 10)
|
|
}
|
|
|
|
@Test func messagesExceedingLimitSplitIntoMultipleChunks() {
|
|
let largeData = String(repeating: "A", count: 60_000_000)
|
|
let attachment = iMessageAttachment(
|
|
filename: "large.bin",
|
|
mimeType: "application/octet-stream",
|
|
transferName: "large.bin",
|
|
size: 60_000_000,
|
|
data: largeData
|
|
)
|
|
let messages = (0..<3).map {
|
|
makeTestMessage(guid: "large-\($0)", attachments: [attachment])
|
|
}
|
|
let chunks = ChunkingStrategy.createAdaptiveChunks(messages)
|
|
#expect(chunks.count >= 2)
|
|
}
|
|
|
|
@Test func singleOversizedMessageGetsOwnChunk() {
|
|
let hugeData = String(repeating: "X", count: 110_000_000)
|
|
let attachment = iMessageAttachment(
|
|
filename: "huge.bin",
|
|
mimeType: "application/octet-stream",
|
|
transferName: "huge.bin",
|
|
size: 110_000_000,
|
|
data: hugeData
|
|
)
|
|
let messages = [
|
|
makeTestMessage(guid: "small-1"),
|
|
makeTestMessage(guid: "huge", attachments: [attachment]),
|
|
makeTestMessage(guid: "small-2"),
|
|
]
|
|
let chunks = ChunkingStrategy.createAdaptiveChunks(messages)
|
|
#expect(chunks.count == 3)
|
|
#expect(chunks[0].count == 1)
|
|
#expect(chunks[0][0].guid == "small-1")
|
|
#expect(chunks[1].count == 1)
|
|
#expect(chunks[1][0].guid == "huge")
|
|
#expect(chunks[2].count == 1)
|
|
#expect(chunks[2][0].guid == "small-2")
|
|
}
|
|
|
|
@Test func baseOverheadIsAccounted() {
|
|
#expect(ChunkingStrategy.baseOverhead == 200)
|
|
}
|
|
|
|
@Test func maxChunkSizeBytesIs100MB() {
|
|
#expect(ChunkingStrategy.maxChunkSizeBytes == 100_000_000)
|
|
}
|
|
}
|
|
|
|
@Suite("Message Size Estimation")
|
|
struct MessageSizeEstimationTests {
|
|
|
|
@Test func baseOverheadIs500Bytes() {
|
|
let size = ChunkingStrategy.estimateMessageSize(makeTestMessage(text: nil))
|
|
#expect(size == 500)
|
|
}
|
|
|
|
@Test func textFieldAddsUtf8ByteCount() {
|
|
let text = "Hello, World!"
|
|
let size = ChunkingStrategy.estimateMessageSize(makeTestMessage(text: text))
|
|
#expect(size == 500 + text.utf8.count)
|
|
}
|
|
|
|
@Test func attachmentDataAddsUtf8ByteCount() {
|
|
let data = "base64encodedcontent"
|
|
let attachment = iMessageAttachment(
|
|
filename: "test.jpg",
|
|
mimeType: "image/jpeg",
|
|
transferName: "test.jpg",
|
|
size: 1000,
|
|
data: data
|
|
)
|
|
let size = ChunkingStrategy.estimateMessageSize(makeTestMessage(text: nil, attachments: [attachment]))
|
|
let expected = 500 + 100 + data.utf8.count + "test.jpg".utf8.count + "image/jpeg".utf8.count + "test.jpg".utf8.count
|
|
#expect(size == expected)
|
|
}
|
|
|
|
@Test func multipleAttachmentsSumCorrectly() {
|
|
let att1 = iMessageAttachment(filename: "a.jpg", mimeType: "image/jpeg", transferName: nil, size: 100, data: "AAA")
|
|
let att2 = iMessageAttachment(filename: "b.png", mimeType: "image/png", transferName: nil, size: 200, data: "BBB")
|
|
let size = ChunkingStrategy.estimateMessageSize(makeTestMessage(text: nil, attachments: [att1, att2]))
|
|
let expected = 500
|
|
+ 100 + "AAA".utf8.count + "a.jpg".utf8.count + "image/jpeg".utf8.count
|
|
+ 100 + "BBB".utf8.count + "b.png".utf8.count + "image/png".utf8.count
|
|
#expect(size == expected)
|
|
}
|
|
|
|
@Test func nilOptionalFieldsAddZero() {
|
|
let size = ChunkingStrategy.estimateMessageSize(
|
|
makeTestMessage(text: nil, expressiveSendStyleId: nil, associatedMessageGuid: nil, senderDisplayName: nil)
|
|
)
|
|
#expect(size == 500)
|
|
}
|
|
|
|
@Test func optionalStringFieldsAddToSize() {
|
|
let size = ChunkingStrategy.estimateMessageSize(
|
|
makeTestMessage(
|
|
text: nil,
|
|
expressiveSendStyleId: "com.apple.MobileSMS.expressivesend.impact",
|
|
senderDisplayName: "Alice"
|
|
)
|
|
)
|
|
let expected = 500
|
|
+ "com.apple.MobileSMS.expressivesend.impact".utf8.count
|
|
+ "Alice".utf8.count
|
|
#expect(size == expected)
|
|
}
|
|
}
|