element-ios/RiotTests/PillsFormatterTests.swift

221 lines
9.4 KiB
Swift
Raw Normal View History

2022-05-05 13:04:26 +00:00
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import XCTest
@testable import Element
2022-05-05 13:04:26 +00:00
// MARK: - Inputs
private enum Inputs {
static let messageStart = "Hello "
static let aliceDisplayname = "Alice"
2022-07-12 07:47:12 +00:00
static let aliceUserId = "@alice:matrix.org"
static let aliceAvatarUrl = "mxc://matrix.org/VyNYAgahaiAzUoOeZETtQ"
2022-06-16 15:07:47 +00:00
static let aliceAwayDisplayname = "Alice_away"
static let aliceNewAvatarUrl = "mxc://matrix.org/VyNYAgaFdlLojoOeZETtQ"
2022-07-12 07:47:12 +00:00
static let aliceMember = FakeMXRoomMember(displayname: aliceDisplayname, avatarUrl: aliceAvatarUrl, userId: aliceUserId)
static let aliceMemberAway = FakeMXRoomMember(displayname: aliceAwayDisplayname, avatarUrl: aliceNewAvatarUrl, userId: "@alice:matrix.org")
2022-05-05 13:04:26 +00:00
static let bobMember = FakeMXRoomMember(displayname: "Bob", avatarUrl: "", userId: "@bob:matrix.org")
static let alicePermalink = "https://matrix.to/#/@alice:matrix.org"
static let mentionToAlice = NSAttributedString(string: aliceDisplayname, attributes: [.link: URL(string: alicePermalink)!])
static let markdownLinkToAlice = "[Alice](\(alicePermalink))"
}
// MARK: - Tests
@available(iOS 15.0, *)
class PillsFormatterTests: XCTestCase {
func testPillsInsertionAndRefresh() {
2022-05-05 13:04:26 +00:00
let messageWithPills = createMessageWithMentionFromBobToAlice()
XCTAssertEqual(messageWithPills.length, Inputs.messageStart.count + 1) // +1 non-unicode character for the pill/textAttachment
XCTAssert(messageWithPills.attribute(.attachment, at: messageWithPills.length - 1, effectiveRange: nil) is PillTextAttachment)
let pillTextAttachment = messageWithPills.attribute(.attachment, at: messageWithPills.length - 1, effectiveRange: nil) as? PillTextAttachment
// Alice's pill is highlighted.
XCTAssert(pillTextAttachment?.data?.isHighlighted == true)
// Attachment has correct type.
XCTAssert(pillTextAttachment?.fileType == PillsFormatter.pillUTType)
// Pill data contains Alice's displayname and avatar url.
XCTAssertEqual(pillTextAttachment?.data?.displayText, Inputs.aliceDisplayname)
XCTAssertEqual(pillTextAttachment?.data?.avatarUrl, Inputs.aliceAvatarUrl)
// Pill has expected size.
let expectedSize = PillAttachmentViewProvider.size(forDisplayText: pillTextAttachment!.data!.displayText,
andFont: pillTextAttachment!.data!.font)
XCTAssertEqual(pillTextAttachment?.bounds.size, expectedSize)
PillsFormatter.refreshPills(in: messageWithPills,
with: FakeMXRoomState(roomMembers: FakeMXUpdatedRoomMembers()))
let refreshedPillTextAttachment = messageWithPills.attribute(.attachment, at: messageWithPills.length - 1, effectiveRange: nil) as? PillTextAttachment
// Alice's pill is still highlighted.
XCTAssert(pillTextAttachment?.data?.isHighlighted == true)
// Pill data is refreshed with correct data.
XCTAssertEqual(refreshedPillTextAttachment?.data?.displayText, Inputs.aliceAwayDisplayname)
XCTAssertEqual(refreshedPillTextAttachment?.data?.avatarUrl, Inputs.aliceNewAvatarUrl)
// Pill size is updated
let newExpectedSize = PillAttachmentViewProvider.size(forDisplayText: refreshedPillTextAttachment!.data!.displayText,
andFont: refreshedPillTextAttachment!.data!.font)
XCTAssertEqual(refreshedPillTextAttachment?.bounds.size, newExpectedSize)
2022-05-05 13:04:26 +00:00
}
2022-06-16 15:07:47 +00:00
func testPillsUsingLatestRoomState() {
let messageWithPills = createMessageWithMentionFromBobToAliceWithLatestRoomState()
let pillTextAttachment = messageWithPills.attribute(.attachment, at: messageWithPills.length - 1, effectiveRange: nil) as? PillTextAttachment
// Pill uses the latest room state data.
2022-06-16 15:07:47 +00:00
XCTAssertEqual(pillTextAttachment?.data?.displayText, Inputs.aliceAwayDisplayname)
XCTAssertEqual(pillTextAttachment?.data?.avatarUrl, Inputs.aliceNewAvatarUrl)
2022-06-16 15:07:47 +00:00
}
2022-05-05 13:04:26 +00:00
func testPillsToMarkdown() {
let messageWithPills = createMessageWithMentionFromBobToAlice()
2022-07-12 07:47:12 +00:00
let markdownMessage = PillsFormatter.stringByReplacingPills(in: messageWithPills, mode: .markdown)
2022-05-05 13:04:26 +00:00
XCTAssertEqual(markdownMessage, Inputs.messageStart + Inputs.markdownLinkToAlice)
}
func testPillsToRawBody() {
let messageWithPills = createMessageWithMentionFromBobToAlice()
2022-07-12 07:47:12 +00:00
let messageWithDisplayname = PillsFormatter.stringByReplacingPills(in: messageWithPills, mode: .displayname)
let messageWithUserId = PillsFormatter.stringByReplacingPills(in: messageWithPills, mode: .identifier)
XCTAssertEqual(messageWithDisplayname, Inputs.messageStart + Inputs.aliceDisplayname)
XCTAssertEqual(messageWithUserId, Inputs.messageStart + Inputs.aliceUserId)
2022-05-05 13:04:26 +00:00
}
}
@available(iOS 15.0, *)
private extension PillsFormatterTests {
2022-05-05 13:04:26 +00:00
func createMessageWithMentionFromBobToAlice() -> NSAttributedString {
let formattedMessage = NSMutableAttributedString(string: Inputs.messageStart)
formattedMessage.append(Inputs.mentionToAlice)
2022-05-11 07:11:12 +00:00
let session = FakeMXSession(myUserId: Inputs.aliceMember.userId)
let messageWithPills = PillsFormatter.insertPills(in: formattedMessage,
2022-05-11 07:11:12 +00:00
withSession: session,
eventFormatter: EventFormatter(matrixSession: session),
event: FakeMXEvent(sender: Inputs.bobMember.userId),
2022-06-16 15:07:47 +00:00
roomState: FakeMXRoomState(roomMembers: FakeMXRoomMembers()),
andLatestRoomState: nil)
return messageWithPills
}
func createMessageWithMentionFromBobToAliceWithLatestRoomState() -> NSAttributedString {
let formattedMessage = NSMutableAttributedString(string: Inputs.messageStart)
formattedMessage.append(Inputs.mentionToAlice)
let session = FakeMXSession(myUserId: Inputs.aliceMember.userId)
let messageWithPills = PillsFormatter.insertPills(in: formattedMessage,
withSession: session,
eventFormatter: EventFormatter(matrixSession: session),
event: FakeMXEvent(sender: Inputs.bobMember.userId),
roomState: FakeMXRoomState(roomMembers: FakeMXRoomMembers()),
andLatestRoomState: FakeMXRoomState(roomMembers: FakeMXUpdatedRoomMembers()))
2022-05-05 13:04:26 +00:00
return messageWithPills
}
}
// MARK: - Mock objects
private class FakeMXSession: MXSession {
private var mockMyUserId: String
init(myUserId: String) {
mockMyUserId = myUserId
super.init()
}
override var myUserId: String! {
2022-05-13 15:03:20 +00:00
return mockMyUserId
2022-05-05 13:04:26 +00:00
}
}
private class FakeMXRoomState: MXRoomState {
2022-06-16 15:07:47 +00:00
private let mockRoomMembers: MXRoomMembers
init(roomMembers: MXRoomMembers) {
mockRoomMembers = roomMembers
super.init()
}
2022-05-05 13:04:26 +00:00
override var members: MXRoomMembers! {
2022-06-16 15:07:47 +00:00
return mockRoomMembers
}
}
private class FakeMXUpdatedRoomMembers: MXRoomMembers {
override var members: [MXRoomMember]! {
return [Inputs.aliceMemberAway, Inputs.bobMember]
}
override func member(withUserId userId: String!) -> MXRoomMember! {
return members.first(where: { $0.userId == userId })
2022-05-05 13:04:26 +00:00
}
}
private class FakeMXRoomMembers: MXRoomMembers {
override var members: [MXRoomMember]! {
return [Inputs.aliceMember, Inputs.bobMember]
}
override func member(withUserId userId: String!) -> MXRoomMember! {
return members.first(where: { $0.userId == userId })
}
}
private class FakeMXRoomMember: MXRoomMember {
2022-06-16 15:07:47 +00:00
private let mockDisplayname: String
2022-05-05 13:04:26 +00:00
private var mockAvatarUrl: String
2022-06-16 15:07:47 +00:00
private let mockUserId: String
2022-05-05 13:04:26 +00:00
init(displayname: String, avatarUrl: String, userId: String) {
mockDisplayname = displayname
mockAvatarUrl = avatarUrl
mockUserId = userId
super.init()
}
required init?(coder: NSCoder) {
fatalError()
}
override var displayname: String! {
return mockDisplayname
}
override var avatarUrl: String! {
get { return mockAvatarUrl }
set { mockAvatarUrl = newValue }
}
override var userId: String! {
return mockUserId
}
}
private class FakeMXEvent: MXEvent {
private var mockSender: String
init(sender: String) {
mockSender = sender
super.init()
}
required init?(coder: NSCoder) {
fatalError()
}
override var sender: String! {
get { return mockSender }
set { mockSender = newValue }
}
}