mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
1921 lines
88 KiB
Swift
1921 lines
88 KiB
Swift
import Foundation
|
|
|
|
import UIKit
|
|
import XCTest
|
|
|
|
import Postbox
|
|
@testable import Postbox
|
|
|
|
import SwiftSignalKit
|
|
|
|
private let peerId = PeerId(namespace: 1, id: 1)
|
|
private let otherPeerId = PeerId(namespace: 1, id: 2)
|
|
private let namespace: Int32 = 1
|
|
private let authorPeerId = PeerId(namespace: 1, id: 6)
|
|
private let peer = TestPeer(id: 6, data: "abc")
|
|
private let tag1 = MessageTags(rawValue: 1 << 0)
|
|
private let tag2 = MessageTags(rawValue: 1 << 1)
|
|
private let summaryTag = MessageTags(rawValue: 1 << 2)
|
|
|
|
private func ==(lhs: [Media], rhs: [Media]) -> Bool {
|
|
if lhs.count != rhs.count {
|
|
return false
|
|
}
|
|
|
|
for i in 0 ..< lhs.count {
|
|
if !lhs[i].isEqual(to: rhs[i]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
private enum Entry: Equatable, CustomStringConvertible {
|
|
case MessageEntry(Int32, Int32, String, [Media], MessageFlags, MessageGroupInfo?)
|
|
case Hole(Int32, Int32, Int32)
|
|
|
|
static func Message(_ id: Int32, _ timestamp: Int32, _ text: String, _ media: [Media], _ flags: MessageFlags, _ groupInfo: MessageGroupInfo? = nil) -> Entry {
|
|
return .MessageEntry(id, timestamp, text, media, flags, groupInfo)
|
|
}
|
|
|
|
var description: String {
|
|
switch self {
|
|
case let .MessageEntry(id, timestamp, text, media, flags, groupInfo):
|
|
return "Message(\(id), \(timestamp), \(text), \(media), \(flags), \(String(describing: groupInfo))"
|
|
case let .Hole(min, max, timestamp):
|
|
return "Hole(\(min), \(max), \(timestamp))"
|
|
}
|
|
}
|
|
}
|
|
|
|
private func ==(lhs: Entry, rhs: Entry) -> Bool {
|
|
switch lhs {
|
|
case let .MessageEntry(lhsId, lhsTimestamp, lhsText, lhsMedia, lhsFlags, lhsGroupInfo):
|
|
switch rhs {
|
|
case let .MessageEntry(rhsId, rhsTimestamp, rhsText, rhsMedia, rhsFlags, rhsGroupInfo):
|
|
return lhsId == rhsId && lhsTimestamp == rhsTimestamp && lhsText == rhsText && lhsMedia == rhsMedia && lhsFlags == rhsFlags && lhsGroupInfo == rhsGroupInfo
|
|
case .Hole:
|
|
return false
|
|
}
|
|
case let .Hole(lhsMin, lhsMax, lhsMaxTimestamp):
|
|
switch rhs {
|
|
case .MessageEntry:
|
|
return false
|
|
case let .Hole(rhsMin, rhsMax, rhsMaxTimestamp):
|
|
return lhsMin == rhsMin && lhsMax == rhsMax && lhsMaxTimestamp == rhsMaxTimestamp
|
|
}
|
|
}
|
|
}
|
|
|
|
private class TestEmbeddedMedia: Media, CustomStringConvertible {
|
|
func isSemanticallyEqual(to other: Media) -> Bool {
|
|
return self.isEqual(to: other)
|
|
}
|
|
|
|
var id: MediaId? { return nil }
|
|
var peerIds: [PeerId] = []
|
|
let data: String
|
|
|
|
init(data: String) {
|
|
self.data = data
|
|
}
|
|
|
|
required init(decoder: PostboxDecoder) {
|
|
self.data = decoder.decodeStringForKey("s", orElse: "")
|
|
}
|
|
|
|
func encode(_ encoder: PostboxEncoder) {
|
|
encoder.encodeString(self.data, forKey: "s")
|
|
}
|
|
|
|
func isEqual(to other: Media) -> Bool {
|
|
if let other = other as? TestEmbeddedMedia {
|
|
return self.data == other.data
|
|
}
|
|
return false
|
|
}
|
|
|
|
var description: String {
|
|
return "TestEmbeddedMedia(\(self.data))"
|
|
}
|
|
}
|
|
|
|
private class TestExternalMedia: Media {
|
|
func isSemanticallyEqual(to other: Media) -> Bool {
|
|
return self.isEqual(to: other)
|
|
}
|
|
|
|
let id: MediaId?
|
|
var peerIds: [PeerId] = []
|
|
let data: String
|
|
|
|
init(id: Int64, data: String) {
|
|
self.id = MediaId(namespace: namespace, id: id)
|
|
self.data = data
|
|
}
|
|
|
|
required init(decoder: PostboxDecoder) {
|
|
self.id = MediaId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0))
|
|
self.data = decoder.decodeStringForKey("s", orElse: "")
|
|
}
|
|
|
|
func encode(_ encoder: PostboxEncoder) {
|
|
encoder.encodeInt32(self.id!.namespace, forKey: "i.n")
|
|
encoder.encodeInt64(self.id!.id, forKey: "i.i")
|
|
encoder.encodeString(self.data, forKey: "s")
|
|
}
|
|
|
|
func isEqual(to other: Media) -> Bool {
|
|
if let other = other as? TestExternalMedia {
|
|
return self.id == other.id && self.data == other.data
|
|
}
|
|
return false
|
|
}
|
|
|
|
var description: String {
|
|
return "TestExternalMedia(\(self.id!.id), \(self.data))"
|
|
}
|
|
}
|
|
|
|
private class TestPeer: Peer {
|
|
let associatedPeerId: PeerId? = nil
|
|
|
|
public let notificationSettingsPeerId: PeerId? = nil
|
|
|
|
let associatedPeerIds: [PeerId]? = nil
|
|
|
|
var indexName: PeerIndexNameRepresentation {
|
|
return .title(title: "Test", addressName: nil)
|
|
}
|
|
|
|
let id: PeerId
|
|
let data: String
|
|
|
|
init(id: Int32, data: String) {
|
|
self.id = PeerId(namespace: namespace, id: id)
|
|
self.data = data
|
|
}
|
|
|
|
required init(decoder: PostboxDecoder) {
|
|
self.id = PeerId(namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt32ForKey("i.i", orElse: 0))
|
|
self.data = decoder.decodeStringForKey("s", orElse: "")
|
|
}
|
|
|
|
func encode(_ encoder: PostboxEncoder) {
|
|
encoder.encodeInt32(self.id.namespace, forKey: "i.n")
|
|
encoder.encodeInt32(self.id.id, forKey: "i.i")
|
|
encoder.encodeString(self.data, forKey: "s")
|
|
}
|
|
|
|
func isEqual(_ other: Peer) -> Bool {
|
|
if let other = other as? TestPeer {
|
|
return self.id == other.id && self.data == other.data
|
|
}
|
|
return false
|
|
}
|
|
|
|
var description: String {
|
|
return "TestPeer(\(self.id.id), \(self.data))"
|
|
}
|
|
}
|
|
|
|
private enum MediaEntry: Equatable {
|
|
case Direct(Media, Int)
|
|
case MessageReference(Int32)
|
|
|
|
init(_ entry: DebugMediaEntry) {
|
|
switch entry {
|
|
case let .Direct(media, referenceCount):
|
|
self = .Direct(media, referenceCount)
|
|
case let .MessageReference(index):
|
|
self = .MessageReference(index.id.id)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func ==(lhs: MediaEntry, rhs: MediaEntry) -> Bool {
|
|
switch lhs {
|
|
case let .Direct(lhsMedia, lhsReferenceCount):
|
|
switch rhs {
|
|
case let .Direct(rhsMedia, rhsReferenceCount):
|
|
return lhsMedia.isEqual(to: rhsMedia) && lhsReferenceCount == rhsReferenceCount
|
|
case .MessageReference:
|
|
return false
|
|
}
|
|
case let .MessageReference(lhsId):
|
|
switch rhs {
|
|
case .Direct:
|
|
return false
|
|
case let .MessageReference(rhsId):
|
|
return lhsId == rhsId
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension MessageTags {
|
|
static let First = MessageTags(rawValue: 1 << 0)
|
|
static let Second = MessageTags(rawValue: 1 << 1)
|
|
static let Summary = MessageTags(rawValue: 1 << 2)
|
|
}
|
|
|
|
private final class PendingMessageAction1: PendingMessageActionData {
|
|
init() {
|
|
}
|
|
|
|
init(decoder: PostboxDecoder) {
|
|
}
|
|
|
|
func encode(_ encoder: PostboxEncoder) {
|
|
}
|
|
|
|
func isEqual(to: PendingMessageActionData) -> Bool {
|
|
if let _ = to as? PendingMessageAction1 {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private final class PendingMessageAction2: PendingMessageActionData {
|
|
init() {
|
|
}
|
|
|
|
init(decoder: PostboxDecoder) {
|
|
}
|
|
|
|
func encode(_ encoder: PostboxEncoder) {
|
|
}
|
|
|
|
func isEqual(to: PendingMessageActionData) -> Bool {
|
|
if let _ = to as? PendingMessageAction2 {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private let pendingAction1 = PendingMessageActionType(rawValue: 0)
|
|
private let pendingAction2 = PendingMessageActionType(rawValue: 1)
|
|
|
|
class MessageHistoryTableTests: XCTestCase {
|
|
var valueBox: ValueBox?
|
|
var path: String?
|
|
|
|
var peerTable: PeerTable?
|
|
var globalMessageIdsTable: GlobalMessageIdsTable?
|
|
var indexTable: MessageHistoryIndexTable?
|
|
var mediaTable: MessageMediaTable?
|
|
var historyTable: MessageHistoryTable?
|
|
var historyMetadataTable: MessageHistoryMetadataTable?
|
|
var unsentTable: MessageHistoryUnsentTable?
|
|
var tagsTable: MessageHistoryTagsTable?
|
|
var readStateTable: MessageHistoryReadStateTable?
|
|
var synchronizeReadStateTable: MessageHistorySynchronizeReadStateTable?
|
|
var globallyUniqueMessageIdsTable: MessageGloballyUniqueIdTable?
|
|
var globalTagsTable: GlobalMessageHistoryTagsTable?
|
|
var localTagsTable: LocalMessageHistoryTagsTable?
|
|
var reverseAssociatedTable: ReverseAssociatedPeerTable?
|
|
var textIndexTable: MessageHistoryTextIndexTable?
|
|
var messageHistoryTagsSummaryTable: MessageHistoryTagsSummaryTable?
|
|
var invalidatedMessageHistoryTagsSummaryTable: InvalidatedMessageHistoryTagsSummaryTable?
|
|
var pendingMessageActionsTable: PendingMessageActionsTable?
|
|
var pendingMessageActionsMetadataTable: PendingMessageActionsMetadataTable?
|
|
var groupFeedIndexTable: GroupFeedIndexTable?
|
|
|
|
override class func setUp() {
|
|
super.setUp()
|
|
|
|
declareEncodable(TestEmbeddedMedia.self, f: { TestEmbeddedMedia(decoder: $0) })
|
|
declareEncodable(TestExternalMedia.self, f: { TestExternalMedia(decoder: $0) })
|
|
declareEncodable(TestPeer.self, f: { TestPeer(decoder: $0) })
|
|
declareEncodable(PendingMessageAction1.self, f: PendingMessageAction1.init)
|
|
declareEncodable(PendingMessageAction2.self, f: PendingMessageAction2.init)
|
|
}
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
|
|
var randomId: Int64 = 0
|
|
arc4random_buf(&randomId, 8)
|
|
path = NSTemporaryDirectory() + "\(randomId)"
|
|
self.valueBox = SqliteValueBox(basePath: path!, queue: Queue.mainQueue())
|
|
|
|
let seedConfiguration = SeedConfiguration(initializeChatListWithHole: (topLevel: nil, groups: nil), initializeMessageNamespacesWithHoles: [], existingMessageTags: [.First, .Second, .Summary], messageTagsWithSummary: [.Summary], existingGlobalMessageTags: [], peerNamespacesRequiringMessageTextIndex: [], additionalChatListIndexNamespace: nil, chatMessagesNamespaces: Set())
|
|
|
|
self.globalMessageIdsTable = GlobalMessageIdsTable(valueBox: self.valueBox!, table: GlobalMessageIdsTable.tableSpec(5), namespace: namespace)
|
|
self.historyMetadataTable = MessageHistoryMetadataTable(valueBox: self.valueBox!, table: MessageHistoryMetadataTable.tableSpec(7))
|
|
self.unsentTable = MessageHistoryUnsentTable(valueBox: self.valueBox!, table: MessageHistoryUnsentTable.tableSpec(8))
|
|
self.invalidatedMessageHistoryTagsSummaryTable = InvalidatedMessageHistoryTagsSummaryTable(valueBox: self.valueBox!, table: MessageHistoryTagsSummaryTable.tableSpec(19))
|
|
self.messageHistoryTagsSummaryTable = MessageHistoryTagsSummaryTable(valueBox: self.valueBox!, table: MessageHistoryTagsSummaryTable.tableSpec(16), invalidateTable: self.invalidatedMessageHistoryTagsSummaryTable!)
|
|
self.pendingMessageActionsMetadataTable = PendingMessageActionsMetadataTable(valueBox: self.valueBox!, table: PendingMessageActionsMetadataTable.tableSpec(17))
|
|
self.pendingMessageActionsTable = PendingMessageActionsTable(valueBox: self.valueBox!, table: PendingMessageActionsTable.tableSpec(18), metadataTable: self.pendingMessageActionsMetadataTable!)
|
|
self.tagsTable = MessageHistoryTagsTable(valueBox: self.valueBox!, table: MessageHistoryTagsTable.tableSpec(9), seedConfiguration: seedConfiguration, summaryTable: self.messageHistoryTagsSummaryTable!)
|
|
self.indexTable = MessageHistoryIndexTable(valueBox: self.valueBox!, table: MessageHistoryIndexTable.tableSpec(1), globalMessageIdsTable: self.globalMessageIdsTable!, metadataTable: self.historyMetadataTable!, seedConfiguration: seedConfiguration)
|
|
self.mediaTable = MessageMediaTable(valueBox: self.valueBox!, table: MessageMediaTable.tableSpec(2))
|
|
self.readStateTable = MessageHistoryReadStateTable(valueBox: self.valueBox!, table: MessageHistoryReadStateTable.tableSpec(10))
|
|
self.synchronizeReadStateTable = MessageHistorySynchronizeReadStateTable(valueBox: self.valueBox!, table: MessageHistorySynchronizeReadStateTable.tableSpec(11))
|
|
self.globallyUniqueMessageIdsTable = MessageGloballyUniqueIdTable(valueBox: self.valueBox!, table: MessageGloballyUniqueIdTable.tableSpec(12))
|
|
self.globalTagsTable = GlobalMessageHistoryTagsTable(valueBox: self.valueBox!, table: GlobalMessageHistoryTagsTable.tableSpec(13))
|
|
self.localTagsTable = LocalMessageHistoryTagsTable(valueBox: self.valueBox!, table: GlobalMessageHistoryTagsTable.tableSpec(22))
|
|
self.textIndexTable = MessageHistoryTextIndexTable(valueBox: self.valueBox!, table: MessageHistoryTextIndexTable.tableSpec(15))
|
|
self.groupFeedIndexTable = GroupFeedIndexTable(valueBox: self.valueBox!, table: GroupFeedIndexTable.tableSpec(21), metadataTable: self.historyMetadataTable!)
|
|
self.historyTable = MessageHistoryTable(valueBox: self.valueBox!, table: MessageHistoryTable.tableSpec(4), messageHistoryIndexTable: self.indexTable!, messageMediaTable: self.mediaTable!, historyMetadataTable: self.historyMetadataTable!, globallyUniqueMessageIdsTable: self.globallyUniqueMessageIdsTable!, unsentTable: self.unsentTable!, tagsTable: self.tagsTable!, globalTagsTable: self.globalTagsTable!, localTagsTable: self.localTagsTable!, readStateTable: self.readStateTable!, synchronizeReadStateTable: self.synchronizeReadStateTable!, textIndexTable: self.textIndexTable!, summaryTable: self.messageHistoryTagsSummaryTable!, pendingActionsTable: self.pendingMessageActionsTable!, groupAssociationTable: self.groupAssociationTable!, groupFeedIndexTable: self.groupFeedIndexTable!)
|
|
self.reverseAssociatedTable = ReverseAssociatedPeerTable(valueBox: self.valueBox!, table: ReverseAssociatedPeerTable.tableSpec(14))
|
|
self.peerTable = PeerTable(valueBox: self.valueBox!, table: PeerTable.tableSpec(6), reverseAssociatedTable: self.reverseAssociatedTable!)
|
|
self.peerTable!.set(peer)
|
|
}
|
|
|
|
override func tearDown() {
|
|
super.tearDown()
|
|
|
|
self.historyTable = nil
|
|
self.indexTable = nil
|
|
self.mediaTable = nil
|
|
self.peerTable = nil
|
|
self.historyMetadataTable = nil
|
|
|
|
self.valueBox = nil
|
|
let _ = try? FileManager.default.removeItem(atPath: path!)
|
|
self.path = nil
|
|
}
|
|
|
|
private func addMessage(_ id: Int32, _ timestamp: Int32, _ text: String = "", _ media: [Media] = [], _ flags: StoreMessageFlags = [], _ tags: MessageTags = [], location: AddMessagesLocation = .Random, groupingKey: Int64? = nil) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
let _ = self.historyTable!.addMessages(messages: [StoreMessage(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: groupingKey, timestamp: timestamp, flags: flags, tags: tags, globalTags: [], localTags: [], forwardInfo: StoreMessageForwardInfo(authorId: peerId, sourceId: peerId, sourceMessageId: MessageId(peerId: peerId, namespace: 0, id: 10), date: 10, authorSignature: "abc", isHidden: false), authorId: authorPeerId, text: text, attributes: [], media: media)], location: location, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations, processMessages: nil)
|
|
}
|
|
|
|
private func updateMessage(_ previousId: Int32, _ id: Int32, _ timestamp: Int32, _ text: String = "", _ media: [Media] = [], _ flags: StoreMessageFlags, _ tags: MessageTags, _ groupingKey: Int64?) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.updateMessage(MessageId(peerId: peerId, namespace: namespace, id: previousId), message: StoreMessage(id: MessageId(peerId: peerId, namespace: namespace, id: id), globallyUniqueId: nil, groupingKey: groupingKey, timestamp: timestamp, flags: flags, tags: tags, globalTags: [], localTags: [], forwardInfo: nil, authorId: authorPeerId, text: text, attributes: [], media: media), operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func updateMessageTimestamp(_ previousId: Int32, _ timestamp: Int32) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.updateMessageTimestamp(MessageId(peerId: peerId, namespace: namespace, id: previousId), timestamp: timestamp, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func addHole(_ id: Int32) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.addHoles([MessageId(peerId: peerId, namespace: namespace, id: id)], operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func removeMessages(_ ids: [Int32]) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.removeMessages(ids.map({ MessageId(peerId: peerId, namespace: namespace, id: $0) }), operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func removeMessagesInRange(minId: Int32, maxId: Int32) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.removeMessagesInRange(peerId: peerId, namespace: namespace, minId: minId, maxId: maxId, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func fillHole(_ id: Int32, _ fillType: HoleFill, _ messages: [(Int32, Int32, String, [Media], Int64?)], _ tagMask: MessageTags? = nil) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.fillHole(MessageId(peerId: peerId, namespace: namespace, id: id), fillType: fillType, tagMask: tagMask, messages: messages.map({ StoreMessage(id: MessageId(peerId: peerId, namespace: namespace, id: $0.0), globallyUniqueId: nil, groupingKey: $0.4, timestamp: $0.1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: authorPeerId, text: $0.2, attributes: [], media: $0.3) }), operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func fillMultipleHoles(_ id: Int32, _ fillType: HoleFill, _ messages: [(Int32, Int32, String, [Media], Int64?)], _ tagMask: MessageTags? = nil, _ tags: MessageTags = []) {
|
|
var operationsByPeerId: [PeerId: [MessageHistoryOperation]] = [:]
|
|
var unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] = []
|
|
var updatedPeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] = [:]
|
|
var globalTagsOperations: [GlobalMessageHistoryTagsOperation] = []
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
var groupFeedOperations: [PeerGroupId: [GroupFeedIndexOperation]] = [:]
|
|
var localTagsOperations: [IntermediateMessageHistoryLocalTagsOperation] = []
|
|
var updatedMedia: [MediaId : Media?] = [:]
|
|
|
|
self.historyTable!.fillMultipleHoles(mainHoleId: MessageId(peerId: peerId, namespace: namespace, id: id), fillType: fillType, tagMask: tagMask, messages: messages.map({ StoreMessage(id: MessageId(peerId: peerId, namespace: namespace, id: $0.0), globallyUniqueId: nil, groupingKey: $0.4, timestamp: $0.1, flags: [], tags: tags, globalTags: [], localTags: [], forwardInfo: nil, authorId: authorPeerId, text: $0.2, attributes: [], media: $0.3) }), operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, groupFeedOperations: &groupFeedOperations, localTagsOperations: &localTagsOperations)
|
|
}
|
|
|
|
private func replaceSummary(_ count: Int32, _ maxId: MessageId.Id) {
|
|
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
self.messageHistoryTagsSummaryTable!.replace(key: MessageHistoryTagsSummaryKey(tag: .Summary, peerId: peerId, namespace: namespace), count: count, maxId: maxId, updatedSummaries: &updatedMessageTagSummaries)
|
|
}
|
|
|
|
private func getExistingMessageGroupInfo(_ id: Int32) -> MessageGroupInfo {
|
|
if let entry = self.indexTable!.getMaybeUninitialized(MessageId(peerId: peerId, namespace: namespace, id: id)) {
|
|
if let message = self.historyTable?.getMessage(entry.index) {
|
|
return message.groupInfo!
|
|
}
|
|
}
|
|
preconditionFailure()
|
|
}
|
|
|
|
private func expectEntries(_ entries: [Entry], tagMask: MessageTags? = nil) {
|
|
var stableIds = Set<UInt32>()
|
|
|
|
let list: [RenderedMessageHistoryEntry]
|
|
if let tagMask = tagMask {
|
|
list = self.historyTable!.debugList(tagMask, peerId: peerId, peerTable: self.peerTable!)
|
|
} else {
|
|
list = self.historyTable!.debugList(peerId, peerTable: self.peerTable!)
|
|
}
|
|
|
|
let actualEntries = list.map({ entry -> Entry in
|
|
let stableId: UInt32
|
|
switch entry {
|
|
case let .RenderedMessage(message):
|
|
stableId = message.stableId
|
|
if let messagePeer = message.author {
|
|
if !peer.isEqual(messagePeer) {
|
|
XCTFail("Expected peer \(peer), actual: \(messagePeer)")
|
|
}
|
|
} else {
|
|
XCTFail("Expected peer \(peer), actual: nil")
|
|
}
|
|
if stableIds.contains(stableId) {
|
|
XCTFail("Stable id not unique \(stableId)")
|
|
} else {
|
|
stableIds.insert(stableId)
|
|
}
|
|
return .Message(message.id.id, message.timestamp, message.text, message.media, message.flags, message.groupInfo)
|
|
case let .Hole(hole):
|
|
stableId = hole.stableId
|
|
if stableIds.contains(stableId) {
|
|
XCTFail("Stable id not unique \(stableId)")
|
|
} else {
|
|
stableIds.insert(stableId)
|
|
}
|
|
return .Hole(hole.min, hole.maxIndex.id.id, hole.maxIndex.timestamp)
|
|
}
|
|
})
|
|
if actualEntries != entries {
|
|
XCTFail("Expected\n\(entries)\nActual\n\(actualEntries)")
|
|
}
|
|
}
|
|
|
|
private func expectUnsent(_ indices: [Int32]) {
|
|
let actualUnsent = self.unsentTable!.get().map({ $0.id })
|
|
var match = true
|
|
if actualUnsent.count == indices.count {
|
|
for i in 0 ..< indices.count {
|
|
if indices[i] != actualUnsent[i] {
|
|
match = false
|
|
break
|
|
}
|
|
}
|
|
} else {
|
|
match = false
|
|
}
|
|
if !match {
|
|
XCTFail("Expected\n\(indices)\nActual\n\(actualUnsent)")
|
|
}
|
|
}
|
|
|
|
private func expectMedia(_ media: [MediaEntry]) {
|
|
let actualMedia = self.mediaTable!.debugList().map({MediaEntry($0)})
|
|
if media != actualMedia {
|
|
XCTFail("Expected\n\(media)\nActual\n\(actualMedia)")
|
|
}
|
|
}
|
|
|
|
private func expectSummary(_ summary: MessageHistoryTagNamespaceSummary?) {
|
|
let actualSummary = self.messageHistoryTagsSummaryTable!.get(MessageHistoryTagsSummaryKey(tag: .Summary, peerId: peerId, namespace: namespace))
|
|
if actualSummary != summary {
|
|
XCTFail("Expected\n\(String(describing: summary))\nActual\n\(String(describing: actualSummary))\n")
|
|
}
|
|
}
|
|
|
|
private func setMessageAction(_ id: Int32, _ type: PendingMessageActionType, _ data: PendingMessageActionData?) {
|
|
var pendingActionsOperations: [PendingMessageActionsOperation] = []
|
|
var updatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:]
|
|
var updatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] = [:]
|
|
var invalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = []
|
|
self.historyTable!.setPendingMessageAction(id: MessageId(peerId: peerId, namespace: namespace, id: id), type: type, action: data, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries)
|
|
}
|
|
|
|
private func expectMessageAction(_ id: Int32, _ type: PendingMessageActionType, _ data: PendingMessageActionData?) {
|
|
let current = self.pendingMessageActionsTable!.getAction(id: MessageId(peerId: peerId, namespace: namespace, id: id), type: type)
|
|
var changed = false
|
|
if let current = current, let data = data {
|
|
if !current.isEqual(to: data) {
|
|
changed = true
|
|
}
|
|
} else if (current != nil) != (data != nil) {
|
|
changed = true
|
|
}
|
|
if changed {
|
|
XCTFail("Expected\n\(String(describing: data))\nActual\n\(String(describing: current))\n")
|
|
}
|
|
}
|
|
|
|
private func expectPeerNamespaceMessageActionCount(_ count: Int32) {
|
|
let current = self.pendingMessageActionsMetadataTable!.getCount(.peerNamespace(peerId, namespace))
|
|
if count != current {
|
|
XCTFail("Expected\n\(count)\nActual\n\(current)\n")
|
|
}
|
|
}
|
|
|
|
private func expectPeerNamespaceActionMessageActionCount(_ count: Int32, _ type: PendingMessageActionType) {
|
|
let current = self.pendingMessageActionsMetadataTable!.getCount(.peerNamespaceAction(peerId, namespace, type))
|
|
if count != current {
|
|
XCTFail("Expected\n\(count)\nActual\n\(current)\n")
|
|
}
|
|
}
|
|
|
|
private func expectPeerMessageActions(_ type: PendingMessageActionType, _ actions: [(Int32, PendingMessageActionData)]) {
|
|
let current = self.pendingMessageActionsTable!.getActions(type: type).map {
|
|
($0.id.id, $0.action)
|
|
}
|
|
var changed = false
|
|
if current.count != actions.count {
|
|
changed = true
|
|
} else {
|
|
for i in 0 ..< current.count {
|
|
if current[i].0 != actions[i].0 {
|
|
changed = true
|
|
break
|
|
} else if !current[i].1.isEqual(to: actions[i].1) {
|
|
changed = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if changed {
|
|
XCTFail("Expected\n\(actions)\nActual\n\(current)\n")
|
|
}
|
|
}
|
|
|
|
func testInsertMessageIntoEmpty() {
|
|
addMessage(100, 100, "t100")
|
|
addMessage(200, 200, "t200")
|
|
|
|
expectEntries([.Message(100, 100, "t100", [], []), .Message(200, 200, "t200", [], [])])
|
|
}
|
|
|
|
func testInsertMessageIgnoreOverwrite() {
|
|
addMessage(100, 100, "t100")
|
|
addMessage(100, 200, "t200")
|
|
|
|
expectEntries([.Message(100, 100, "t100", [], [])])
|
|
}
|
|
|
|
func testInsertMessageWithEmbeddedMedia() {
|
|
addMessage(100, 100, "t100", [TestEmbeddedMedia(data: "abc1")])
|
|
|
|
expectEntries([.Message(100, 100, "t100", [TestEmbeddedMedia(data: "abc1")], [])])
|
|
expectMedia([])
|
|
}
|
|
|
|
func testInsertMessageWithExternalMedia() {
|
|
let media = TestExternalMedia(id: 10, data: "abc1")
|
|
addMessage(100, 100, "t100", [media])
|
|
|
|
expectEntries([.Message(100, 100, "t100", [media], [])])
|
|
expectMedia([.MessageReference(100)])
|
|
}
|
|
|
|
func testUnembedExternalMedia() {
|
|
let media = TestExternalMedia(id: 10, data: "abc1")
|
|
addMessage(100, 100, "t100", [media])
|
|
addMessage(200, 200, "t200", [media])
|
|
|
|
expectEntries([.Message(100, 100, "t100", [media], []), .Message(200, 200, "t200", [media], [])])
|
|
expectMedia([.Direct(media, 2)])
|
|
}
|
|
|
|
func testIgnoreOverrideExternalMedia() {
|
|
let media = TestExternalMedia(id: 10, data: "abc1")
|
|
let media1 = TestExternalMedia(id: 10, data: "abc2")
|
|
addMessage(100, 100, "t100", [media])
|
|
addMessage(200, 200, "t200", [media1])
|
|
|
|
expectEntries([.Message(100, 100, "t100", [media], []), .Message(200, 200, "t200", [media], [])])
|
|
expectMedia([.Direct(media, 2)])
|
|
}
|
|
|
|
func testRemoveSingleMessage() {
|
|
addMessage(100, 100, "t100", [])
|
|
|
|
removeMessages([100])
|
|
|
|
expectEntries([])
|
|
expectMedia([])
|
|
}
|
|
|
|
func testRemoveMessageWithEmbeddedMedia() {
|
|
let media = TestEmbeddedMedia(data: "abc1")
|
|
addMessage(100, 100, "t100", [media])
|
|
self.removeMessages([100])
|
|
|
|
expectEntries([])
|
|
expectMedia([])
|
|
}
|
|
|
|
func testRemoveOnlyReferenceToExternalMedia() {
|
|
let media = TestExternalMedia(id: 10, data: "abc1")
|
|
addMessage(100, 100, "t100", [media])
|
|
removeMessages([100])
|
|
|
|
expectEntries([])
|
|
expectMedia([])
|
|
}
|
|
|
|
func testRemoveReferenceToExternalMedia() {
|
|
let media = TestExternalMedia(id: 10, data: "abc1")
|
|
addMessage(100, 100, "t100", [media])
|
|
addMessage(200, 200, "t200", [media])
|
|
removeMessages([100])
|
|
|
|
expectEntries([.Message(200, 200, "t200", [media], [])])
|
|
expectMedia([.Direct(media, 1)])
|
|
|
|
removeMessages([200])
|
|
|
|
expectEntries([])
|
|
expectMedia([])
|
|
}
|
|
|
|
func testAddHoleToEmpty() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddHoleToFullHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
addHole(110)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageToFullHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
addMessage(90, 90, "m90")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageDividingUpperHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
addMessage(90, 90, "m90")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
addMessage(100, 100, "m100")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, 99, 100), .Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageDividingLowerHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
addMessage(90, 90, "m90")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
addMessage(80, 80, "m80")
|
|
expectEntries([.Hole(1, 79, 80), .Message(80, 80, "m80", [], []), .Hole(81, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageOffsettingUpperHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
|
|
addMessage(90, 90, "m90")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
addMessage(91, 91, "m91")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Message(91, 91, "m91", [], []), .Hole(92, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageOffsettingLowerHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
|
|
addMessage(90, 90, "m90")
|
|
expectEntries([.Hole(1, 89, 90), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
addMessage(89, 89, "m89")
|
|
expectEntries([.Hole(1, 88, 89), .Message(89, 89, "m89", [], []), .Message(90, 90, "m90", [], []), .Hole(91, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageOffsettingLeftmostHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
|
|
addMessage(1, 1, "m1")
|
|
|
|
expectEntries([.Message(1, 1, "m1", [], []), .Hole(2, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddMessageRemovingLefmostHole() {
|
|
addHole(100)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
|
|
addMessage(2, 2, "m2")
|
|
expectEntries([.Hole(1, 1, 2), .Message(2, 2, "m2", [], []), .Hole(3, Int32.max, Int32.max)])
|
|
|
|
addMessage(1, 1, "m1")
|
|
expectEntries([.Message(1, 1, "m1", [], []), .Message(2, 2, "m2", [], []), .Hole(3, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddHoleLowerThanMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(1)
|
|
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], [])])
|
|
}
|
|
|
|
func testAddHoleHigherThanMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(200)
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testIgnoreHigherHole() {
|
|
addHole(200)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
addHole(400)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testIgnoreHigherHoleAfterMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(200)
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)])
|
|
addHole(400)
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testAddHoleBetweenMessages() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
addHole(150)
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testFillHoleEmpty() {
|
|
fillHole(1, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [])
|
|
expectEntries([])
|
|
}
|
|
|
|
func testFillHoleComplete() {
|
|
addHole(100)
|
|
|
|
fillHole(1, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(100, 100, "m100", [], nil), (200, 200, "m200", [], nil)])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testFillHoleUpperToLowerPartial() {
|
|
addHole(100)
|
|
|
|
fillHole(1, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(100, 100, "m100", [], nil), (200, 200, "m200", [], nil)])
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], []), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testFillHoleUpperToLowerToBounds() {
|
|
addHole(100)
|
|
|
|
fillHole(1, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(1, 1, "m1", [], nil), (200, 200, "m200", [], nil)])
|
|
expectEntries([.Message(1, 1, "m1", [], []), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testFillHoleLowerToUpperToBounds() {
|
|
addHole(100)
|
|
|
|
fillHole(1, HoleFill(complete: false, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [(100, 100, "m100", [], nil), (Int32.max, 200, "m200", [], nil)])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(Int32.max, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testFillHoleLowerToUpperPartial() {
|
|
addHole(100)
|
|
|
|
fillHole(1, HoleFill(complete: false, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [(100, 100, "m100", [], nil), (200, 200, "m200", [], nil)])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(200, 200, "m200", [], []), .Hole(201, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testFillHoleBetweenMessagesUpperToLower() {
|
|
addHole(1)
|
|
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(150, 150, "m150", [], nil)])
|
|
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], []), .Hole(101, 149, 150), .Message(150, 150, "m150", [], []), .Message(200, 200, "m200", [], []), .Hole(201, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testFillHoleBetweenMessagesLowerToUpper() {
|
|
addHole(1)
|
|
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [(150, 150, "m150", [], nil)])
|
|
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], []), .Message(150, 150, "m150", [], []), .Hole(151, 199, 200), .Message(200, 200, "m200", [], []), .Hole(201, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testFillHoleBetweenMessagesComplete() {
|
|
addHole(1)
|
|
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
|
|
fillHole(199, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(150, 150, "m150", [], nil)])
|
|
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], []), .Message(150, 150, "m150", [], []), .Message(200, 200, "m200", [], []), .Hole(201, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testFillHoleBetweenMessagesWithMessage() {
|
|
addMessage(200, 200, "m200")
|
|
addMessage(202, 202, "m202")
|
|
addHole(201)
|
|
addMessage(201, 201, "m201")
|
|
|
|
expectEntries([.Message(200, 200, "m200", [], []), .Message(201, 201, "m201", [], []), .Message(202, 202, "m202", [], [])])
|
|
}
|
|
|
|
func testFillHoleWithNoMessagesComplete() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(1)
|
|
|
|
fillHole(99, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])])
|
|
}
|
|
|
|
func testFillHoleIgnoreOverMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(101, 101, "m101")
|
|
|
|
fillHole(100, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(90, 90, "m90", [], nil)])
|
|
|
|
expectEntries([.Message(90, 90, "m90", [], []), .Message(100, 100, "m100", [], []), .Message(101, 101, "m101", [], [])])
|
|
}
|
|
|
|
func testFillHoleWithOverflow() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(150, 150, "m150", [], nil), (300, 300, "m300", [], nil)])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 149, 150), .Message(150, 150, "m150", [], []), .Message(200, 200, "m200", [], []), .Message(300, 300, "m300", [], [])])
|
|
}
|
|
|
|
func testIgnoreHoleOverMessageBetweenMessages() {
|
|
addMessage(199, 199, "m199")
|
|
addMessage(200, 200, "m200")
|
|
addHole(200)
|
|
|
|
expectEntries([.Message(199, 199, "m199", [], []), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testMergeHoleAfterDeletingMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(1)
|
|
addHole(200)
|
|
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)])
|
|
|
|
removeMessages([100])
|
|
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testMergeHoleLowerAfterDeletingMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(1)
|
|
addMessage(200, 200, "m200")
|
|
|
|
removeMessages([100])
|
|
|
|
expectEntries([.Hole(1, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testMergeHoleUpperAfterDeletingMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
addHole(300)
|
|
|
|
removeMessages([200])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testExtendLowerHoleAfterDeletingMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(100)
|
|
|
|
removeMessages([100])
|
|
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testExtendUpperHoleAfterDeletingMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addHole(101)
|
|
|
|
removeMessages([100])
|
|
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)])
|
|
}
|
|
|
|
func testDeleteMessageBelowMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
removeMessages([100])
|
|
|
|
expectEntries([.Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testDeleteMessageAboveMessage() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
removeMessages([200])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])])
|
|
}
|
|
|
|
func testDeleteMessageBetweenMessages() {
|
|
addMessage(100, 100, "m100")
|
|
addMessage(200, 200, "m200")
|
|
addMessage(300, 300, "m300")
|
|
removeMessages([200])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(300, 300, "m300", [], [])])
|
|
}
|
|
|
|
func testAddUnsent() {
|
|
addMessage(100, 100, "m100", [], [.Unsent])
|
|
expectEntries([.Message(100, 100, "m100", [], [.Unsent])])
|
|
expectUnsent([100])
|
|
}
|
|
|
|
func testRemoveUnsent() {
|
|
addMessage(100, 100, "m100", [], [.Unsent])
|
|
expectEntries([.Message(100, 100, "m100", [], [.Unsent])])
|
|
expectUnsent([100])
|
|
|
|
removeMessages([100])
|
|
expectEntries([])
|
|
expectUnsent([])
|
|
}
|
|
|
|
func testUpdateUnsentToSentSameIndex() {
|
|
addMessage(100, 100, "m100", [], [.Unsent])
|
|
expectEntries([.Message(100, 100, "m100", [], [.Unsent])])
|
|
expectUnsent([100])
|
|
|
|
updateMessage(100, 100, 100, "m100", [], [], [], nil)
|
|
expectEntries([.Message(100, 100, "m100", [], [])])
|
|
expectUnsent([])
|
|
}
|
|
|
|
func testUpdateUnsentToFailed() {
|
|
addMessage(100, 100, "m100", [], [.Unsent])
|
|
expectEntries([.Message(100, 100, "m100", [], [.Unsent])])
|
|
expectUnsent([100])
|
|
|
|
updateMessage(100, 100, 100, "m100", [], [.Unsent, .Failed], [], nil)
|
|
expectEntries([.Message(100, 100, "m100", [], [.Unsent, .Failed])])
|
|
expectUnsent([])
|
|
}
|
|
|
|
func testUpdateDifferentIndex() {
|
|
addMessage(100, 100, "m100", [], [.Unsent])
|
|
expectEntries([.Message(100, 100, "m100", [], [.Unsent])])
|
|
expectUnsent([100])
|
|
|
|
updateMessage(100, 200, 200, "m100", [], [], [], nil)
|
|
expectEntries([.Message(200, 200, "m100", [], [])])
|
|
expectUnsent([])
|
|
}
|
|
|
|
func testUpdateDifferentIndexBreakHole() {
|
|
addHole(1)
|
|
|
|
addMessage(100, 100, "m100", [], [.Unsent])
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], [.Unsent]), .Hole(101, Int32.max, Int32.max)])
|
|
expectUnsent([100])
|
|
|
|
updateMessage(100, 200, 200, "m100", [], [], [], nil)
|
|
expectEntries([.Hole(1, 199, 200), .Message(200, 200, "m100", [], []), .Hole(201, Int32.max, Int32.max)])
|
|
expectUnsent([])
|
|
}
|
|
|
|
func testInsertTaggedIntoEmpty() {
|
|
addMessage(100, 100, "m100", [], [], MessageTags(rawValue: 1))
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: MessageTags(rawValue: 1))
|
|
}
|
|
|
|
func testInsertMultipleTagsIntoEmpty() {
|
|
addMessage(200, 200, "m200", [], [], MessageTags(rawValue: 2))
|
|
addMessage(100, 100, "m100", [], [], MessageTags(rawValue: 1 | 2))
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: MessageTags(rawValue: 1))
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(200, 200, "m200", [], [])], tagMask: MessageTags(rawValue: 2))
|
|
}
|
|
|
|
func testRemoveSingleTagged() {
|
|
addMessage(100, 100, "m100", [], [], MessageTags(rawValue: 1))
|
|
removeMessages([100])
|
|
|
|
expectEntries([], tagMask: MessageTags(rawValue: 1))
|
|
}
|
|
|
|
func testRemoveMultipleTagged() {
|
|
addMessage(200, 200, "m200", [], [], MessageTags(rawValue: 2))
|
|
addMessage(100, 100, "m100", [], [], MessageTags(rawValue: 1 | 2))
|
|
removeMessages([100])
|
|
expectEntries([], tagMask: MessageTags(rawValue: 1))
|
|
expectEntries([.Message(200, 200, "m200", [], [])], tagMask: MessageTags(rawValue: 2))
|
|
}
|
|
|
|
func testTagsInsertHoleIntoEmpty() {
|
|
addHole(1)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)], tagMask: [.First])
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)], tagMask: [.Second])
|
|
}
|
|
|
|
func testTagsBreakHoleWithMessage() {
|
|
addHole(1)
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
|
|
expectEntries([.Hole(1, 99, 100), .Message(100, 100, "m100", [], []), .Hole(101, Int32.max, Int32.max)], tagMask: [.First])
|
|
expectEntries([.Hole(1, 99, 100), .Hole(101, Int32.max, Int32.max)], tagMask: [.Second])
|
|
}
|
|
|
|
func testTagsFillHoleUpperToLowerAllTags() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(180, 180, "m180", [], nil)])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 179, 180)], tagMask: [.First])
|
|
expectEntries([.Hole(101, 179, 180), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 179, 180), .Message(180, 180, "m180", [], []), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleLowerToUpperAllTags() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [(180, 180, "m180", [], nil)])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(181, 199, 200)], tagMask: [.First])
|
|
expectEntries([.Hole(181, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(180, 180, "m180", [], []), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleCompleteAllTags() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(180, 180, "m180", [], nil)])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: [.First])
|
|
expectEntries([.Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Message(180, 180, "m180", [], []), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleUpperToLowerSingleTagWithMessages() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(180, 180, "m180", [], nil)], [.First])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 179, 180)], tagMask: [.First])
|
|
expectEntries([.Hole(101, 179, 180), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 179, 180), .Message(180, 180, "m180", [], []), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleLowerToUpperSingleTagWithMessages() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [(180, 180, "m180", [], nil)], [.First])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(181, 199, 200)], tagMask: [.First])
|
|
expectEntries([.Hole(101, 179, 180), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 179, 180), .Message(180, 180, "m180", [], []), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleCompleteSingleTagWithMessages() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(180, 180, "m180", [], nil)], [.First])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: [.First])
|
|
expectEntries([.Hole(101, 179, 180), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 179, 180), .Message(180, 180, "m180", [], []), .Hole(181, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleUpperToLowerSingleTagWithEmpty() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [], [.First])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: [.First])
|
|
expectEntries([.Hole(101, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleLowerToUpperSingleTagWithEmpty() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: false, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [], [.First])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: [.First])
|
|
expectEntries([.Hole(101, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillHoleCompleteSingleTagWithEmpty() {
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.Second])
|
|
addHole(150)
|
|
|
|
fillHole(199, HoleFill(complete: true, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [], [.First])
|
|
|
|
expectEntries([.Message(100, 100, "m100", [], [])], tagMask: [.First])
|
|
expectEntries([.Hole(101, 199, 200), .Message(200, 200, "m200", [], [])], tagMask: [.Second])
|
|
expectEntries([.Message(100, 100, "m100", [], []), .Hole(101, 199, 200), .Message(200, 200, "m200", [], [])])
|
|
}
|
|
|
|
func testTagsFillMultipleHolesSingleHole() {
|
|
addHole(1)
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
addMessage(200, 200, "m200", [], [], [.First])
|
|
addMessage(300, 300, "m300", [], [], [.First])
|
|
addMessage(400, 400, "m400", [], [], [.First])
|
|
|
|
expectEntries([
|
|
.Hole(1, 99, 100),
|
|
.Message(100, 100, "m100", [], []),
|
|
.Hole(101, 199, 200),
|
|
.Message(200, 200, "m200", [], []),
|
|
.Hole(201, 299, 300),
|
|
.Message(300, 300, "m300", [], []),
|
|
.Hole(301, 399, 400),
|
|
.Message(400, 400, "m400", [], []),
|
|
.Hole(401, Int32.max, Int32.max)
|
|
], tagMask: [.First])
|
|
|
|
expectEntries([
|
|
.Hole(1, 99, 100),
|
|
.Hole(101, 199, 200),
|
|
.Hole(201, 299, 300),
|
|
.Hole(301, 399, 400),
|
|
.Hole(401, Int32.max, Int32.max)
|
|
], tagMask: [.Second])
|
|
|
|
fillMultipleHoles(500, HoleFill(complete: false, direction: .UpperToLower(updatedMinIndex: nil, clippingMaxIndex: nil)), [(500, 500, "m500", [], nil), (350, 350, "m350", [], nil)], [.Second], [.Second])
|
|
|
|
expectEntries([
|
|
.Hole(1, 99, 100),
|
|
.Hole(101, 199, 200),
|
|
.Hole(201, 299, 300),
|
|
.Hole(301, 349, 350),
|
|
.Message(350, 350, "m350", [], []),
|
|
.Message(500, 500, "m500", [], [])
|
|
], tagMask: [.Second])
|
|
|
|
expectEntries([
|
|
.Hole(1, 99, 100),
|
|
.Message(100, 100, "m100", [], []),
|
|
.Hole(101, 199, 200),
|
|
.Message(200, 200, "m200", [], []),
|
|
.Hole(201, 299, 300),
|
|
.Message(300, 300, "m300", [], []),
|
|
.Hole(301, 349, 350),
|
|
.Hole(351, 399, 400),
|
|
.Message(400, 400, "m400", [], []),
|
|
.Hole(401, 499, 500),
|
|
.Hole(501, Int32.max, Int32.max)
|
|
], tagMask: [.First])
|
|
}
|
|
|
|
func testFullTextGetEmpty() {
|
|
XCTAssert(self.textIndexTable!.search(peerId: nil, text: "abc", tags: nil).isEmpty)
|
|
}
|
|
|
|
func testFullTextMatch1() {
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 1), text: "a b c", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 2), text: "a b c d", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 3), text: "c d e", tags: [])
|
|
|
|
var result = self.textIndexTable!.search(peerId: nil, text: "a", tags: nil).sorted()
|
|
let testIds1: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 1),
|
|
MessageId(peerId: peerId, namespace: 0, id: 2),
|
|
]
|
|
XCTAssert(result == testIds1)
|
|
|
|
result = self.textIndexTable!.search(peerId: nil, text: "c", tags: nil).sorted()
|
|
let testIds2: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 1),
|
|
MessageId(peerId: peerId, namespace: 0, id: 2),
|
|
MessageId(peerId: peerId, namespace: 0, id: 3)
|
|
]
|
|
XCTAssert(result == testIds2)
|
|
|
|
result = self.textIndexTable!.search(peerId: nil, text: "d", tags: nil).sorted()
|
|
let testIds3: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 2),
|
|
MessageId(peerId: peerId, namespace: 0, id: 3)
|
|
]
|
|
XCTAssert(result == testIds3)
|
|
|
|
result = self.textIndexTable!.search(peerId: nil, text: "a b c", tags: nil).sorted()
|
|
XCTAssert(result == testIds1)
|
|
|
|
result = self.textIndexTable!.search(peerId: nil, text: "a b c d e", tags: nil).sorted()
|
|
let testIds4: [MessageId] = [
|
|
]
|
|
XCTAssert(result == testIds4)
|
|
|
|
self.textIndexTable!.remove(messageId: MessageId(peerId: peerId, namespace: 0, id: 2))
|
|
let testIds5: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 1),
|
|
MessageId(peerId: peerId, namespace: 0, id: 3)
|
|
]
|
|
result = self.textIndexTable!.search(peerId: nil, text: "c", tags: nil).sorted()
|
|
XCTAssert(result == testIds5)
|
|
}
|
|
|
|
func testFullTextMatchLocal() {
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 1), text: "a b c", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 2), text: "a b c d", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: otherPeerId, namespace: 0, id: 1), text: "c d e", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: otherPeerId, namespace: 0, id: 2), text: "d e f", tags: [])
|
|
|
|
var result = self.textIndexTable!.search(peerId: peerId, text: "a", tags: nil).sorted()
|
|
let testIds1: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 1),
|
|
MessageId(peerId: peerId, namespace: 0, id: 2),
|
|
]
|
|
XCTAssert(result == testIds1)
|
|
|
|
result = self.textIndexTable!.search(peerId: otherPeerId, text: "c", tags: nil).sorted()
|
|
let testIds2: [MessageId] = [
|
|
MessageId(peerId: otherPeerId, namespace: 0, id: 1),
|
|
]
|
|
XCTAssert(result == testIds2)
|
|
|
|
result = self.textIndexTable!.search(peerId: otherPeerId, text: "d", tags: nil).sorted()
|
|
let testIds3: [MessageId] = [
|
|
MessageId(peerId: otherPeerId, namespace: 0, id: 1),
|
|
MessageId(peerId: otherPeerId, namespace: 0, id: 2)
|
|
]
|
|
XCTAssert(result == testIds3)
|
|
}
|
|
|
|
func testFullTextMatchLocalTags() {
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 1), text: "a b c", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 2), text: "a b c d", tags: [])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 3), text: "a b c", tags: [tag1])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 4), text: "a b c", tags: [tag1, tag2])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 5), text: "a b c", tags: [tag1, tag2])
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 6), text: "a b c", tags: [tag2])
|
|
|
|
var result = self.textIndexTable!.search(peerId: peerId, text: "a b c", tags: nil).sorted()
|
|
let testIds1: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 1),
|
|
MessageId(peerId: peerId, namespace: 0, id: 2),
|
|
MessageId(peerId: peerId, namespace: 0, id: 3),
|
|
MessageId(peerId: peerId, namespace: 0, id: 4),
|
|
MessageId(peerId: peerId, namespace: 0, id: 5),
|
|
MessageId(peerId: peerId, namespace: 0, id: 6),
|
|
]
|
|
XCTAssert(result == testIds1)
|
|
|
|
result = self.textIndexTable!.search(peerId: peerId, text: "a b c", tags: [tag1]).sorted()
|
|
let testIds2: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 3),
|
|
MessageId(peerId: peerId, namespace: 0, id: 4),
|
|
MessageId(peerId: peerId, namespace: 0, id: 5),
|
|
]
|
|
XCTAssert(result == testIds2)
|
|
|
|
result = self.textIndexTable!.search(peerId: peerId, text: "a b c", tags: [tag2]).sorted()
|
|
let testIds3: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 4),
|
|
MessageId(peerId: peerId, namespace: 0, id: 5),
|
|
MessageId(peerId: peerId, namespace: 0, id: 6),
|
|
]
|
|
XCTAssert(result == testIds3)
|
|
|
|
result = self.textIndexTable!.search(peerId: peerId, text: "a b c", tags: [tag1, tag2]).sorted()
|
|
let testIds4: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 4),
|
|
MessageId(peerId: peerId, namespace: 0, id: 5),
|
|
]
|
|
XCTAssert(result == testIds4)
|
|
}
|
|
|
|
func testFullTextEscape1() {
|
|
self.textIndexTable!.add(messageId: MessageId(peerId: peerId, namespace: 0, id: 1), text: "abc' def'", tags: [])
|
|
var result = self.textIndexTable!.search(peerId: nil, text: "abc'", tags: nil).sorted()
|
|
let testIds1: [MessageId] = [
|
|
MessageId(peerId: peerId, namespace: 0, id: 1)
|
|
]
|
|
XCTAssert(result == testIds1)
|
|
|
|
result = self.textIndexTable!.search(peerId: nil, text: "abc' def'", tags: nil).sorted()
|
|
XCTAssert(result == testIds1)
|
|
|
|
result = self.textIndexTable!.search(peerId: nil, text: "abc' AND def", tags: nil).sorted()
|
|
XCTAssert(result.isEmpty)
|
|
}
|
|
|
|
func testSummary1() {
|
|
expectSummary(nil)
|
|
addMessage(100, 100, "m100", [], [], [.First])
|
|
expectSummary(nil)
|
|
addMessage(200, 200, "m200", [], [], [.Summary])
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 0, count: 1, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 0)))
|
|
replaceSummary(2, 200)
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 2, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
addMessage(150, 150, "m200", [], [], [.Summary])
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 2, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
removeMessages([150])
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 1, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
removeMessages([200])
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 0, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
addMessage(300, 300, "m300", [], [], [.Summary])
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 1, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
addHole(400)
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 1, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
}
|
|
|
|
func testSummary2() {
|
|
addHole(400)
|
|
expectSummary(nil)
|
|
}
|
|
|
|
func testSummary3() {
|
|
addMessage(200, 200, "m200", [], [], [.Summary])
|
|
addHole(100)
|
|
replaceSummary(0, 200)
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 0, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
addMessage(300, 300, "m300", [], [], [.Summary])
|
|
addHole(250)
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 1, count: 1, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 200)))
|
|
replaceSummary(10, 300)
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 2, count: 10, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 300)))
|
|
self.updateMessage(300, 300, 300, "m300", [], [], [], nil)
|
|
expectSummary(MessageHistoryTagNamespaceSummary(version: 2, count: 9, range: MessageHistoryTagNamespaceCountValidityRange(maxId: 300)))
|
|
}
|
|
|
|
func testPendingMessageActions1() {
|
|
expectMessageAction(100, pendingAction1, nil)
|
|
expectPeerNamespaceMessageActionCount(0)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction1)
|
|
setMessageAction(100, pendingAction1, PendingMessageAction1())
|
|
expectMessageAction(100, pendingAction1, nil)
|
|
expectPeerNamespaceMessageActionCount(0)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction1)
|
|
addMessage(100, 100)
|
|
expectMessageAction(100, pendingAction1, nil)
|
|
expectPeerNamespaceMessageActionCount(0)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction1)
|
|
setMessageAction(100, pendingAction1, PendingMessageAction1())
|
|
expectMessageAction(100, pendingAction1, PendingMessageAction1())
|
|
expectPeerNamespaceMessageActionCount(1)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction2)
|
|
removeMessages([100])
|
|
expectMessageAction(100, pendingAction1, nil)
|
|
expectPeerNamespaceMessageActionCount(0)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction2)
|
|
|
|
addMessage(100, 100)
|
|
setMessageAction(100, pendingAction1, PendingMessageAction1())
|
|
expectPeerNamespaceMessageActionCount(1)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction2)
|
|
|
|
setMessageAction(100, pendingAction1, PendingMessageAction1())
|
|
expectPeerNamespaceMessageActionCount(1)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction2)
|
|
|
|
setMessageAction(100, pendingAction2, PendingMessageAction2())
|
|
expectPeerNamespaceMessageActionCount(2)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction2)
|
|
|
|
addMessage(200, 200)
|
|
setMessageAction(200, pendingAction1, PendingMessageAction1())
|
|
expectPeerNamespaceMessageActionCount(3)
|
|
expectPeerNamespaceActionMessageActionCount(2, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction2)
|
|
expectPeerMessageActions(pendingAction1, [(100, PendingMessageAction1()), (200, PendingMessageAction1())])
|
|
expectPeerMessageActions(pendingAction2, [(100, PendingMessageAction2())])
|
|
|
|
removeMessages([100])
|
|
expectPeerNamespaceMessageActionCount(1)
|
|
expectPeerNamespaceActionMessageActionCount(1, pendingAction1)
|
|
expectPeerNamespaceActionMessageActionCount(0, pendingAction2)
|
|
expectPeerMessageActions(pendingAction2, [])
|
|
expectPeerMessageActions(pendingAction1, [(200, PendingMessageAction1())])
|
|
}
|
|
|
|
func testRemoveRangeEmpty() {
|
|
removeMessagesInRange(minId: 0, maxId: Int32.max)
|
|
expectEntries([], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeOneMessage1() {
|
|
addMessage(100, 100)
|
|
expectEntries([.Message(100, 100, "", [], [])], tagMask: nil)
|
|
removeMessagesInRange(minId: 0, maxId: 99)
|
|
expectEntries([.Message(100, 100, "", [], [])], tagMask: nil)
|
|
removeMessagesInRange(minId: 101, maxId: Int32.max)
|
|
expectEntries([.Message(100, 100, "", [], [])], tagMask: nil)
|
|
removeMessagesInRange(minId: 0, maxId: Int32.max)
|
|
expectEntries([], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeOneMessage2() {
|
|
addMessage(100, 100)
|
|
expectEntries([.Message(100, 100, "", [], [])], tagMask: nil)
|
|
removeMessagesInRange(minId: 100, maxId: Int32.max)
|
|
expectEntries([], tagMask: nil)
|
|
addMessage(100, 100)
|
|
removeMessagesInRange(minId: 0, maxId: 100)
|
|
expectEntries([], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole1() {
|
|
addHole(1)
|
|
removeMessagesInRange(minId: 0, maxId: Int32.max)
|
|
expectEntries([], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole2() {
|
|
addHole(1)
|
|
removeMessagesInRange(minId: 0, maxId: 100)
|
|
expectEntries([.Hole(101, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole3() {
|
|
addHole(1)
|
|
removeMessagesInRange(minId: 100, maxId: Int32.max)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole4() {
|
|
addMessage(100, 100)
|
|
addMessage(200, 200)
|
|
addHole(101)
|
|
addHole(1)
|
|
addHole(201)
|
|
removeMessagesInRange(minId: 0, maxId: Int32.max)
|
|
expectEntries([], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole5() {
|
|
addMessage(100, 100)
|
|
addMessage(200, 200)
|
|
addHole(101)
|
|
addHole(1)
|
|
addHole(201)
|
|
removeMessagesInRange(minId: 0, maxId: 99)
|
|
expectEntries([.Message(100, 100, "", [], []),
|
|
.Hole(101, 199, 200),
|
|
.Message(200, 200, "", [], []),
|
|
.Hole(201, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole6() {
|
|
addMessage(100, 100)
|
|
addMessage(200, 200)
|
|
addHole(101)
|
|
addHole(1)
|
|
addHole(201)
|
|
removeMessagesInRange(minId: 0, maxId: 50)
|
|
expectEntries([.Hole(51, 99, 100),
|
|
.Message(100, 100, "", [], []),
|
|
.Hole(101, 199, 200),
|
|
.Message(200, 200, "", [], []),
|
|
.Hole(201, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole7() {
|
|
addMessage(100, 100)
|
|
addMessage(200, 200)
|
|
addHole(101)
|
|
addHole(1)
|
|
addHole(201)
|
|
removeMessagesInRange(minId: 50, maxId: 150)
|
|
expectEntries([.Hole(1, 199, 200),
|
|
.Message(200, 200, "", [], []),
|
|
.Hole(201, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole8() {
|
|
addMessage(100, 100)
|
|
addMessage(200, 200)
|
|
addHole(101)
|
|
addHole(1)
|
|
addHole(201)
|
|
removeMessagesInRange(minId: 0, maxId: 200)
|
|
expectEntries([.Hole(1, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testRemoveRangeHole9() {
|
|
addMessage(100, 100)
|
|
addMessage(200, 200)
|
|
addHole(101)
|
|
addHole(1)
|
|
addHole(201)
|
|
removeMessagesInRange(minId: 0, maxId: 300)
|
|
expectEntries([.Hole(301, Int32.max, Int32.max)], tagMask: nil)
|
|
}
|
|
|
|
func testAddHole1() {
|
|
addMessage(100, 100)
|
|
addMessage(101, 101)
|
|
addMessage(102, 102)
|
|
|
|
addHole(Int32.max)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], []),
|
|
.Message(101, 101, "", [], []),
|
|
.Message(102, 102, "", [], []),
|
|
.Hole(103, Int32.max, Int32.max)
|
|
], tagMask: nil)
|
|
|
|
addMessage(104, 104, location: .UpperHistoryBlock)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], []),
|
|
.Message(101, 101, "", [], []),
|
|
.Message(102, 102, "", [], []),
|
|
.Hole(103, 103, 104),
|
|
.Message(104, 104, "", [], []),
|
|
], tagMask: nil)
|
|
}
|
|
|
|
/*None,A,None -> None, A(D), None
|
|
None,A,A(D) -> None, A(D), None
|
|
A(D),A,None -> A(D), A(D), None
|
|
None,A,B(D1) -> None, A(D2), B(D1)
|
|
A(D),A,A(D) -> A(D),A(D),A(D)
|
|
A(D1),A,B(D2) -> A(D1), A(D1), B(D2)
|
|
B(D1),A,None -> B(D1), A(D2), None
|
|
B(D1),A,A(D2) -> B(D1), A(D2), A(D2)
|
|
|
|
B(D1),A,B(D1) -> B(D1), A(D2), B(D3)
|
|
*/
|
|
|
|
func testGroupNoneNone() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo = getExistingMessageGroupInfo(100)
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo)
|
|
])
|
|
}
|
|
|
|
func testGroupHoleHole() {
|
|
addHole(1)
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo = getExistingMessageGroupInfo(100)
|
|
expectEntries([
|
|
.Hole(1, 99, 100),
|
|
.Message(100, 100, "", [], [], groupInfo),
|
|
.Hole(101, Int32.max, Int32.max)
|
|
])
|
|
}
|
|
|
|
func testGroupSameNone() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo = getExistingMessageGroupInfo(100)
|
|
addMessage(110, 110, groupingKey: 1)
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo),
|
|
.Message(110, 110, "", [], [], groupInfo)
|
|
])
|
|
}
|
|
|
|
func testGroupNoneSame() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo = getExistingMessageGroupInfo(100)
|
|
addMessage(90, 90, groupingKey: 1)
|
|
expectEntries([
|
|
.Message(90, 90, "", [], [], groupInfo),
|
|
.Message(100, 100, "", [], [], groupInfo)
|
|
])
|
|
}
|
|
|
|
func testGroupNoneOther() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
addMessage(90, 90, groupingKey: 2)
|
|
let groupInfo2 = getExistingMessageGroupInfo(90)
|
|
expectEntries([
|
|
.Message(90, 90, "", [], [], groupInfo2),
|
|
.Message(100, 100, "", [], [], groupInfo1)
|
|
])
|
|
}
|
|
|
|
func testGroupSameSame() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo = getExistingMessageGroupInfo(100)
|
|
addMessage(90, 90, groupingKey: 1)
|
|
addMessage(95, 95, groupingKey: 1)
|
|
expectEntries([
|
|
.Message(90, 90, "", [], [], groupInfo),
|
|
.Message(95, 95, "", [], [], groupInfo),
|
|
.Message(100, 100, "", [], [], groupInfo)
|
|
])
|
|
}
|
|
|
|
func testGroupSameOther() {
|
|
addMessage(100, 100, groupingKey: 2)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
addMessage(90, 90, groupingKey: 1)
|
|
let groupInfo2 = getExistingMessageGroupInfo(90)
|
|
addMessage(95, 95, groupingKey: 1)
|
|
expectEntries([
|
|
.Message(90, 90, "", [], [], groupInfo2),
|
|
.Message(95, 95, "", [], [], groupInfo2),
|
|
.Message(100, 100, "", [], [], groupInfo1)
|
|
])
|
|
}
|
|
|
|
func testGroupOtherNone() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
addMessage(110, 110, groupingKey: 2)
|
|
let groupInfo2 = getExistingMessageGroupInfo(110)
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(110, 110, "", [], [], groupInfo2)
|
|
])
|
|
}
|
|
|
|
func testGroupOtherSame() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
addMessage(110, 110, groupingKey: 2)
|
|
let groupInfo2 = getExistingMessageGroupInfo(110)
|
|
addMessage(105, 105, groupingKey: 2)
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(105, 105, "", [], [], groupInfo2),
|
|
.Message(110, 110, "", [], [], groupInfo2)
|
|
])
|
|
}
|
|
|
|
func testGroupOtherOtherTailSingle() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
|
|
addMessage(110, 110, groupingKey: 2)
|
|
let groupInfo2 = getExistingMessageGroupInfo(110)
|
|
|
|
let groupInfo3 = getExistingMessageGroupInfo(120)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(110, 110, "", [], [], groupInfo2),
|
|
.Message(120, 120, "", [], [], groupInfo3)
|
|
])
|
|
|
|
XCTAssert(groupInfo3 != groupInfo1 && groupInfo3 != groupInfo2)
|
|
}
|
|
|
|
func testGroupOtherOtherTailMultiple() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: 1)
|
|
addMessage(130, 130, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
|
|
addMessage(110, 110, groupingKey: 2)
|
|
let groupInfo2 = getExistingMessageGroupInfo(110)
|
|
|
|
let groupInfo3 = getExistingMessageGroupInfo(120)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(110, 110, "", [], [], groupInfo2),
|
|
.Message(120, 120, "", [], [], groupInfo3),
|
|
.Message(130, 130, "", [], [], groupInfo3),
|
|
.Message(140, 140, "", [], [], groupInfo3)
|
|
])
|
|
|
|
XCTAssert(groupInfo3 != groupInfo1 && groupInfo3 != groupInfo2)
|
|
}
|
|
|
|
func testGroupBreakWithHole() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: 1)
|
|
addMessage(130, 130, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
|
|
addHole(110)
|
|
|
|
let groupInfo3 = getExistingMessageGroupInfo(120)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Hole(101, 119, 120),
|
|
.Message(120, 120, "", [], [], groupInfo3),
|
|
.Message(130, 130, "", [], [], groupInfo3),
|
|
.Message(140, 140, "", [], [], groupInfo3)
|
|
])
|
|
|
|
XCTAssert(groupInfo3 != groupInfo1)
|
|
}
|
|
|
|
func testGroupCombine1() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: nil)
|
|
addMessage(130, 130, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
let groupInfo2 = getExistingMessageGroupInfo(130)
|
|
|
|
removeMessages([120])
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(130, 130, "", [], [], groupInfo1),
|
|
.Message(140, 140, "", [], [], groupInfo1)
|
|
])
|
|
|
|
XCTAssert(groupInfo1 != groupInfo2)
|
|
}
|
|
|
|
func testGroupCombine2() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: nil)
|
|
addMessage(125, 125, groupingKey: nil)
|
|
addMessage(130, 130, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
addMessage(150, 150, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
let groupInfo2 = getExistingMessageGroupInfo(130)
|
|
|
|
removeMessages([120, 125, 140])
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(130, 130, "", [], [], groupInfo1),
|
|
.Message(150, 150, "", [], [], groupInfo1)
|
|
])
|
|
|
|
XCTAssert(groupInfo1 != groupInfo2)
|
|
}
|
|
|
|
func testGroupCombine3() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
addMessage(150, 150, groupingKey: 1)
|
|
addHole(120)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
let groupInfo2 = getExistingMessageGroupInfo(140)
|
|
|
|
fillHole(120, HoleFill(complete: true, direction: .LowerToUpper(updatedMaxIndex: nil, clippingMinIndex: nil)), [
|
|
(110, 110, "", [], 1),
|
|
(115, 115, "", [], 1)
|
|
])
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(110, 110, "", [], [], groupInfo1),
|
|
.Message(115, 115, "", [], [], groupInfo1),
|
|
.Message(140, 140, "", [], [], groupInfo1),
|
|
.Message(150, 150, "", [], [], groupInfo1)
|
|
])
|
|
|
|
XCTAssert(groupInfo1 != groupInfo2)
|
|
}
|
|
|
|
func testGroupBreakWithUpdate1() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: 1)
|
|
addMessage(130, 130, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
|
|
updateMessage(120, 150, 150, "", [], [], [], 1)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(130, 130, "", [], [], groupInfo1),
|
|
.Message(140, 140, "", [], [], groupInfo1),
|
|
.Message(150, 150, "", [], [], groupInfo1)
|
|
])
|
|
}
|
|
|
|
func testGroupBreakWithUpdate2() {
|
|
addMessage(100, 100, groupingKey: 1)
|
|
addMessage(120, 120, groupingKey: 1)
|
|
addMessage(130, 130, groupingKey: 1)
|
|
addMessage(140, 140, groupingKey: 1)
|
|
let groupInfo1 = getExistingMessageGroupInfo(100)
|
|
|
|
updateMessage(120, 150, 150, "", [], [], [], 2)
|
|
|
|
let groupInfo2 = getExistingMessageGroupInfo(150)
|
|
|
|
expectEntries([
|
|
.Message(100, 100, "", [], [], groupInfo1),
|
|
.Message(130, 130, "", [], [], groupInfo1),
|
|
.Message(140, 140, "", [], [], groupInfo1),
|
|
.Message(150, 150, "", [], [], groupInfo2)
|
|
])
|
|
|
|
XCTAssert(groupInfo1 != groupInfo2)
|
|
}
|
|
}
|