Skip to content

Commit a5de50a

Browse files
committed
Add MessageLabel tests around detector attributes
1 parent 36f7524 commit a5de50a

11 files changed

Lines changed: 137 additions & 34 deletions

MessageKit.xcodeproj/project.pbxproj

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
1F066E131FD90BB600E11013 /* MessagesViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7FC8CB1FD2700B006CC979 /* MessagesViewControllerSpec.swift */; };
11+
1F066E141FD90BB700E11013 /* MessageLabelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F066E101FD90A0600E11013 /* MessageLabelSpec.swift */; };
1012
1F087D451FD274FD00E95A45 /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1F7FC8C71FD26F49006CC979 /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1113
1F087D461FD274FD00E95A45 /* Quick.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1F7FC8C51FD26F33006CC979 /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
1214
1F7FC8C61FD26F33006CC979 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F7FC8C51FD26F33006CC979 /* Quick.framework */; };
1315
1F7FC8C81FD26F49006CC979 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F7FC8C71FD26F49006CC979 /* Nimble.framework */; };
14-
1F7FC8CC1FD2700B006CC979 /* MessagesViewControllerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F7FC8CB1FD2700B006CC979 /* MessagesViewControllerSpec.swift */; };
1516
1F82D1431FB1B75B00B81A88 /* AvatarPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F82D1421FB1B75B00B81A88 /* AvatarPosition.swift */; };
1617
38C57C791F9AE3E50043CC03 /* SeparatorLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38C57C781F9AE3E50043CC03 /* SeparatorLine.swift */; };
1718
38C57C7C1F9AE4890043CC03 /* InputStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38C57C7B1F9AE4870043CC03 /* InputStackView.swift */; };
@@ -103,6 +104,7 @@
103104
/* End PBXCopyFilesBuildPhase section */
104105

105106
/* Begin PBXFileReference section */
107+
1F066E101FD90A0600E11013 /* MessageLabelSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageLabelSpec.swift; sourceTree = "<group>"; };
106108
1F7FC8C31FD26F22006CC979 /* Carthage */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Carthage; sourceTree = "<group>"; };
107109
1F7FC8C51FD26F33006CC979 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = "<group>"; };
108110
1F7FC8C71FD26F49006CC979 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/iOS/Nimble.framework; sourceTree = "<group>"; };
@@ -300,8 +302,9 @@
300302
8962AC7C1F87AB230030B058 /* ControllersTest */ = {
301303
isa = PBXGroup;
302304
children = (
303-
8962AC7D1F87AB230030B058 /* MessagesViewControllerTests.swift */,
305+
1F066E101FD90A0600E11013 /* MessageLabelSpec.swift */,
304306
1F7FC8CB1FD2700B006CC979 /* MessagesViewControllerSpec.swift */,
307+
8962AC7D1F87AB230030B058 /* MessagesViewControllerTests.swift */,
305308
);
306309
path = ControllersTest;
307310
sourceTree = "<group>";
@@ -619,13 +622,14 @@
619622
buildActionMask = 2147483647;
620623
files = (
621624
8962AC8C1F87AB7D0030B058 /* AvatarViewTests.swift in Sources */,
625+
1F066E141FD90BB700E11013 /* MessageLabelSpec.swift in Sources */,
622626
8962AC971F87AB860030B058 /* DetectorTypeTests.swift in Sources */,
623627
8962AC941F87AB860030B058 /* MessageKitDateFormatterTests.swift in Sources */,
624628
8962AC8E1F87AB7D0030B058 /* InputTextViewTests.swift in Sources */,
625629
8962AC911F87AB860030B058 /* MessagesViewControllerTests.swift in Sources */,
626630
8962AC901F87AB7D0030B058 /* MessageDateHeaderViewTests.swift in Sources */,
627631
8962AC8F1F87AB7D0030B058 /* MessageInputBarTests.swift in Sources */,
628-
1F7FC8CC1FD2700B006CC979 /* MessagesViewControllerSpec.swift in Sources */,
632+
1F066E131FD90BB600E11013 /* MessagesViewControllerSpec.swift in Sources */,
629633
8962AC8A1F87AB7D0030B058 /* MessagesCollectionViewTests.swift in Sources */,
630634
8962AC8D1F87AB7D0030B058 /* MessageCollectionViewCellTests.swift in Sources */,
631635
8962AC961F87AB860030B058 /* SenderTests.swift in Sources */,

Sources/Controllers/MessagesViewController.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,12 @@ open class MessagesViewController: UIViewController {
6666
open override func viewDidLoad() {
6767
super.viewDidLoad()
6868

69-
7069
extendedLayoutIncludesOpaqueBars = true
7170
automaticallyAdjustsScrollViewInsets = false
7271
view.backgroundColor = .white
7372
messagesCollectionView.keyboardDismissMode = .interactive
7473
messagesCollectionView.alwaysBounceVertical = true
7574

76-
7775
setupSubviews()
7876
setupConstraints()
7977
registerReusableViews()

Sources/Layout/MessageIntermediateLayoutAttributes.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424

2525
import Foundation
2626

27-
2827
/// A intermediate context used to store recently calculated values used by
2928
/// the `MessagesCollectionViewFlowLayout` object to reduce redundant calculations.
3029
final class MessageIntermediateLayoutAttributes {

Sources/Layout/MessagesCollectionViewFlowLayout.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ fileprivate extension MessagesCollectionViewFlowLayout {
309309

310310
return position
311311
}
312-
313-
312+
314313
// B
315314

316315
/// Returns the size of the `AvatarView` for a given `MessageType`.
@@ -473,7 +472,6 @@ private extension MessagesCollectionViewFlowLayout {
473472
let avatarVertical = attributes.avatarPosition.vertical
474473
let avatarWidth = attributes.avatarSize.width
475474

476-
477475
switch (labelHorizontal, avatarHorizontal) {
478476

479477
case (.cellLeading, _), (.cellTrailing, _):
@@ -631,4 +629,3 @@ private extension MessagesCollectionViewFlowLayout {
631629
}
632630

633631
}
634-

Sources/Protocols/MessagesDisplayDelegate.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,6 @@ public protocol MessagesDisplayDelegate: AnyObject {
144144
/// - messagesCollectionView: The collection view requesting the information
145145
/// - Returns: Your customized animation block.
146146
func animationBlockForLocation(message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> ((UIImageView) -> Void)?
147-
148-
149147
}
150148

151149
public extension MessagesDisplayDelegate {

Sources/Protocols/MessagesLayoutDelegate.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ public protocol MessagesLayoutDelegate: AnyObject {
155155
/// rect using the `maxWidth` and `.greatestFiniteMagnitude` for the height.
156156
func heightForMedia(message: MessageType, at indexPath: IndexPath, with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat
157157

158-
159158
// MARK: - Location Messages
160159

161160
/// Specifies the width for a `MessageContainerView`.
@@ -267,5 +266,3 @@ public extension MessagesLayoutDelegate {
267266
}
268267

269268
}
270-
271-

Sources/Views/MessageLabel.swift

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,31 +59,41 @@ open class MessageLabel: UILabel {
5959

6060
open var enabledDetectors: [DetectorType] = [] {
6161
didSet {
62-
setTextStorage(shouldParse: true)
62+
setTextStorage(attributedText, shouldParse: true)
6363
}
6464
}
6565

6666
open override var attributedText: NSAttributedString? {
67-
didSet {
68-
setTextStorage(shouldParse: true)
67+
get {
68+
return textStorage
69+
}
70+
set {
71+
setTextStorage(newValue, shouldParse: true)
6972
}
7073
}
7174

7275
open override var text: String? {
73-
didSet {
74-
setTextStorage(shouldParse: true)
76+
get {
77+
return textStorage.string
78+
}
79+
set {
80+
if let text = newValue {
81+
attributedText = NSAttributedString(string: text)
82+
} else {
83+
attributedText = nil
84+
}
7585
}
7686
}
7787

7888
open override var font: UIFont! {
7989
didSet {
80-
setTextStorage(shouldParse: false)
90+
setTextStorage(attributedText, shouldParse: false)
8191
}
8292
}
8393

8494
open override var textColor: UIColor! {
8595
didSet {
86-
setTextStorage(shouldParse: false)
96+
setTextStorage(attributedText, shouldParse: false)
8797
}
8898
}
8999

@@ -103,7 +113,7 @@ open class MessageLabel: UILabel {
103113

104114
open override var textAlignment: NSTextAlignment {
105115
didSet {
106-
setTextStorage(shouldParse: false)
116+
setTextStorage(attributedText, shouldParse: false)
107117
}
108118
}
109119

@@ -192,18 +202,18 @@ open class MessageLabel: UILabel {
192202

193203
// MARK: - Private Methods
194204

195-
private func setTextStorage(shouldParse: Bool) {
205+
private func setTextStorage(_ newText: NSAttributedString?, shouldParse: Bool) {
196206

197-
guard let attributedText = attributedText, attributedText.length > 0 else {
207+
guard let newText = newText, newText.length > 0 else {
198208
textStorage.setAttributedString(NSAttributedString())
199209
setNeedsDisplay()
200210
return
201211
}
202212

203-
let style = paragraphStyle(for: attributedText)
204-
let range = NSRange(location: 0, length: attributedText.length)
213+
let style = paragraphStyle(for: newText)
214+
let range = NSRange(location: 0, length: newText.length)
205215

206-
let mutableText = NSMutableAttributedString(attributedString: attributedText)
216+
let mutableText = NSMutableAttributedString(attributedString: newText)
207217
mutableText.addAttribute(.paragraphStyle, value: style, range: range)
208218

209219
if shouldParse {
@@ -246,14 +256,15 @@ open class MessageLabel: UILabel {
246256
guard let attributedText = attributedText, attributedText.length > 0 else { return }
247257
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
248258

249-
guard let ranges = rangesForDetectors[detectorType] else { return }
259+
guard let rangeTuples = rangesForDetectors[detectorType] else { return }
250260

251-
ranges.forEach { (range, _) in
261+
for (range, _) in rangeTuples {
252262
let attributes = detectorAttributes(for: detectorType)
253263
mutableAttributedString.addAttributes(attributes, range: range)
254264
}
255265

256-
textStorage.setAttributedString(mutableAttributedString)
266+
let updatedString = NSAttributedString(attributedString: mutableAttributedString)
267+
textStorage.setAttributedString(updatedString)
257268

258269
}
259270

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
MIT License
3+
4+
Copyright (c) 2017 MessageKit
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+
*/
24+
25+
import Quick
26+
import Nimble
27+
@testable import MessageKit
28+
29+
final class MessageLabelSpec: QuickSpec {
30+
31+
//swiftlint:disable function_body_length
32+
override func spec() {
33+
34+
var messageLabel: MessageLabel!
35+
36+
beforeEach {
37+
messageLabel = MessageLabel()
38+
}
39+
40+
describe("text recognized by a DetectorType") {
41+
context("address detection is enabled") {
42+
it("applies addressAttributes to text") {
43+
let expectedColor = UIColor.blue
44+
messageLabel.addressAttributes = [.foregroundColor: expectedColor]
45+
messageLabel.text = "One Infinite Loop Cupertino, CA 95014"
46+
messageLabel.enabledDetectors = [.address]
47+
var attributes = messageLabel.textAttributes
48+
var textColor = attributes?[.foregroundColor] as? UIColor
49+
expect(textColor).toNot(beNil())
50+
expect(textColor).to(equal(expectedColor))
51+
}
52+
}
53+
context("phone number detection is enabled") {
54+
it("applies phoneNumberAttributes to text") {
55+
let expectedFont = UIFont.systemFont(ofSize: 8)
56+
messageLabel.phoneNumberAttributes = [.font: expectedFont]
57+
messageLabel.text = "1-800-555-1234"
58+
messageLabel.enabledDetectors = [.phoneNumber]
59+
let attributes = messageLabel.textAttributes
60+
let textFont = attributes?[.font] as? UIFont
61+
expect(textFont).toNot(beNil())
62+
expect(textFont).to(equal(expectedFont))
63+
}
64+
}
65+
context("url detection is enabled") {
66+
it("applies urlAttributes to text") {
67+
let expectedColor = UIColor.green
68+
messageLabel.urlAttributes = [.foregroundColor: expectedColor]
69+
messageLabel.text = "https://github.com/MessageKit"
70+
messageLabel.enabledDetectors = [.url]
71+
let attributes = messageLabel.textAttributes
72+
let textColor = attributes?[.foregroundColor] as? UIColor
73+
expect(textColor).toNot(beNil())
74+
expect(textColor).to(equal(expectedColor))
75+
}
76+
}
77+
context("date detection is enabled") {
78+
it("applies dateAttributes to text") {
79+
let expectedFont = UIFont.italicSystemFont(ofSize: 22)
80+
messageLabel.dateAttributes = [.font: expectedFont]
81+
messageLabel.text = "Today"
82+
messageLabel.enabledDetectors = [.date]
83+
let attributes = messageLabel.textAttributes
84+
let textFont = attributes?[.font] as? UIFont
85+
expect(textFont).toNot(beNil())
86+
expect(textFont).to(equal(expectedFont))
87+
}
88+
}
89+
}
90+
}
91+
}
92+
93+
// MARK: - Helpers
94+
95+
fileprivate extension MessageLabel {
96+
97+
var textAttributes: [NSAttributedStringKey: Any]? {
98+
let length = attributedText!.length
99+
var range = NSRange(location: 0, length: length)
100+
return attributedText?.attributes(at: 0, effectiveRange: &range)
101+
}
102+
}

Tests/ControllersTest/MessagesViewControllerSpec.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ final class MessagesViewControllerSpec: QuickSpec {
3737
}
3838

3939
describe("default property values") {
40-
4140
it("does not scroll to bottom on first layout") {
4241
expect(controller.scrollsToBottomOnFirstLayout).to(beFalse())
4342
}

Tests/ControllersTest/MessagesViewControllerTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ class MessagesViewControllerTests: XCTestCase {
6666
XCTAssertTrue(layout is MessagesCollectionViewFlowLayout)
6767
}
6868

69-
7069
func testViewDidLoad_shouldAddMessageCollectionViewInSubviews() {
7170
let messageColelctionViews = sut.view.subviews.filter { $0 is MessagesCollectionView }
7271

0 commit comments

Comments
 (0)