element-ios/RiotTests/MatrixKitTests/MXKRoomDataSourceTests.swift

150 lines
5.4 KiB
Swift

/*
Copyright 2024 New Vector Ltd.
Copyright 2021 The Matrix.org Foundation C.I.C
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/
import Foundation
import XCTest
@testable import Element
class MXKRoomDataSourceTests: XCTestCase {
// MARK: - Destruction tests
func testDestroyRemovesAllBubbles() {
let dataSource = StubMXKRoomDataSource()
dataSource.destroy()
XCTAssert(dataSource.getBubbles()?.isEmpty != false)
}
func testDestroyDeallocatesAllBubbles() throws {
let dataSource = StubMXKRoomDataSource()
weak var first = try XCTUnwrap(dataSource.getBubbles()?.first)
weak var last = try XCTUnwrap(dataSource.getBubbles()?.last)
dataSource.destroy()
XCTAssertNil(first)
XCTAssertNil(last)
}
// MARK: - Collapsing tests
func testCollapseBubblesWhenProcessingTogether() throws {
let dataSource = try FakeMXKRoomDataSource.make()
try dataSource.queueEvent1()
try dataSource.queueEvent2()
awaitEventProcessing(for: dataSource)
dataSource.verifyCollapsedEvents(2)
}
func testCollapseBubblesWhenProcessingAlone() throws {
let dataSource = try FakeMXKRoomDataSource.make()
try dataSource.queueEvent1()
awaitEventProcessing(for: dataSource)
try dataSource.queueEvent2()
awaitEventProcessing(for: dataSource)
dataSource.verifyCollapsedEvents(2)
}
private func awaitEventProcessing(for dataSource: MXKRoomDataSource) {
let e = expectation(description: "The wai-ai-ting is the hardest part")
dataSource.processQueuedEvents { _, _ in
e.fulfill()
}
waitForExpectations(timeout: 2) { error in
XCTAssertNil(error)
}
}
}
// MARK: - Test doubles
private final class StubMXKRoomDataSource: MXKRoomDataSource {
override init() {
super.init()
let data1 = MXKRoomBubbleCellData()
let data2 = MXKRoomBubbleCellData()
let data3 = MXKRoomBubbleCellData()
data1.nextCollapsableCellData = data2
data2.prevCollapsableCellData = data1
data2.nextCollapsableCellData = data3
data3.prevCollapsableCellData = data2
replaceBubbles([data1, data2, data3])
}
}
private final class FakeMXKRoomDataSource: MXKRoomDataSource {
class func make() throws -> FakeMXKRoomDataSource {
let dataSource = try XCTUnwrap(FakeMXKRoomDataSource(roomId: "!foofoofoofoofoofoo:matrix.org", andMatrixSession: nil, threadId: nil))
dataSource.registerCellDataClass(CollapsibleBubbleCellData.self, forCellIdentifier: kMXKRoomBubbleCellDataIdentifier)
dataSource.eventFormatter = CountingEventFormatter(matrixSession: nil)
return dataSource
}
override var state: MXKDataSourceState {
MXKDataSourceStateReady
}
override var roomState: MXRoomState! {
nil
}
func queueEvent1() throws {
try queueEvent(json: #"{"sender":"@alice:matrix.org","content":{"displayname":"bob","membership":"invite"},"origin_server_ts":1616488993287,"state_key":"@bob:matrix.org","room_id":"!foofoofoofoofoofoo:matrix.org","event_id":"$lGK3budX5w009ErtQwE9ZFhwyUUAV9DqEN5yb2fI4Do","type":"m.room.member","unsigned":{"age":1204610,"prev_sender":"@alice:matrix.org","prev_content":{"membership":"leave"},"replaces_state":"$9mQ6RtscXqHCxWqOElI-eP_kwpkuPd2Czm3UHviGoyE"}}"#)
}
func queueEvent2() throws {
try queueEvent(json: #"{"sender":"@alice:matrix.org","content":{"displayname":"john","membership":"invite"},"origin_server_ts":1616488967295,"state_key":"@john:matrix.org","room_id":"!foofoofoofoofoofoo:matrix.org","event_id":"$-00slfAluxVTP2VWytgDThTmh3nLd0WJD6gzBo2scJM","type":"m.room.member","unsigned":{"age":1712006,"prev_sender":"@alice:matrix.org","prev_content":{"membership":"leave"},"replaces_state":"$NRNkCMKeKK5NtTfWkMfTlMr5Ygw60Q2CQYnJNkbzyrs"}}"#)
}
private func queueEvent(json: String) throws {
let data = try XCTUnwrap(json.data(using: .utf8))
let dict = try XCTUnwrap((try JSONSerialization.jsonObject(with: data, options: [])) as? [AnyHashable: Any])
let event = MXEvent(fromJSON: dict)
queueEvent(forProcessing: event, with: nil, direction: .forwards)
}
func verifyCollapsedEvents(_ number: Int) {
let message = getBubbles()?.first?.collapsedAttributedTextMessage.string
XCTAssertEqual(message, "\(number)")
}
}
private final class CollapsibleBubbleCellData: MXKRoomBubbleCellData {
override init() {
super.init()
}
required init!(event: MXEvent!, andRoomState roomState: MXRoomState!, andRoomDataSource roomDataSource: MXKRoomDataSource!) {
super.init(event: event, andRoomState: roomState, andRoomDataSource: roomDataSource)
collapsable = true
}
override func collapse(with cellData: MXKRoomBubbleCellDataStoring!) -> Bool {
true
}
}
private final class CountingEventFormatter: MXKEventFormatter {
override func attributedString(from events: [MXEvent]!,
with roomState: MXRoomState!,
andLatestRoomState latestRoomState: MXRoomState!,
error: UnsafeMutablePointer<MXKEventFormatterError>!) -> NSAttributedString! {
NSAttributedString(string: "\(events.count)")
}
}