diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 8fc0f8fc1..c0888091c 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 3400C7931EAF89CD008A8584 /* SendExternalFileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3400C7911EAF89CD008A8584 /* SendExternalFileViewController.m */; }; 3400C7961EAF99F4008A8584 /* SelectThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3400C7951EAF99F4008A8584 /* SelectThreadViewController.m */; }; 3400C7991EAFB772008A8584 /* ThreadViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3400C7981EAFB772008A8584 /* ThreadViewHelper.m */; }; + 340B02BA1FA0D6C700F9CFEC /* ConversationViewItemTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 340B02B91FA0D6C700F9CFEC /* ConversationViewItemTest.m */; }; 340CB2241EAC155C0001CAA1 /* ContactsViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 340CB2231EAC155C0001CAA1 /* ContactsViewHelper.m */; }; 340CB2271EAC25820001CAA1 /* UpdateGroupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340CB2261EAC25820001CAA1 /* UpdateGroupViewController.m */; }; 341F2C0F1F2B8AE700D07D6B /* DebugUIMisc.m in Sources */ = {isa = PBXBuildFile; fileRef = 341F2C0E1F2B8AE700D07D6B /* DebugUIMisc.m */; }; @@ -60,7 +61,6 @@ 34B3F8911E8DF1710035BE1A /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86B1E8DF1700035BE1A /* ShowGroupMembersViewController.m */; }; 34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */; }; 34B3F8941E8DF1710035BE1A /* HomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8701E8DF1700035BE1A /* HomeViewController.m */; }; - 34B3F8991E8DF1B90035BE1A /* TSMessageAdapterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8981E8DF1B90035BE1A /* TSMessageAdapterTest.m */; }; 34B3F89C1E8DF3270035BE1A /* BlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F89B1E8DF3270035BE1A /* BlockListViewController.m */; }; 34B3F89F1E8DF5490035BE1A /* OWSTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F89E1E8DF5490035BE1A /* OWSTableViewController.m */; }; 34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */; }; @@ -71,6 +71,10 @@ 34C42D5B1F45F7A80072EC04 /* OWSNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D5A1F45F7A80072EC04 /* OWSNavigationController.m */; }; 34C42D661F4734ED0072EC04 /* OWSContactOffersInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */; }; 34C42D671F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m in Sources */ = {isa = PBXBuildFile; fileRef = 34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */; }; + 34C6B0A91FA0E46F00D35993 /* test-gif.gif in Resources */ = {isa = PBXBuildFile; fileRef = 34C6B0A51FA0E46F00D35993 /* test-gif.gif */; }; + 34C6B0AB1FA0E46F00D35993 /* test-mp3.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 34C6B0A71FA0E46F00D35993 /* test-mp3.mp3 */; }; + 34C6B0AC1FA0E46F00D35993 /* test-mp4.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 34C6B0A81FA0E46F00D35993 /* test-mp4.mp4 */; }; + 34C6B0AE1FA0E4AA00D35993 /* test-jpg.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 34C6B0AD1FA0E4AA00D35993 /* test-jpg.jpg */; }; 34CA1C251F706B5400E51C51 /* NSAttributedString+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CA1C241F706B5400E51C51 /* NSAttributedString+OWS.m */; }; 34CA1C271F7156F300E51C51 /* MessageMetadataViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34CA1C261F7156F300E51C51 /* MessageMetadataViewController.swift */; }; 34CA1C291F7164F700E51C51 /* MediaMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34CA1C281F7164F700E51C51 /* MediaMessageView.swift */; }; @@ -315,7 +319,6 @@ B660F6D81C29868000687D6E /* CryptoToolsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B660F6A71C29868000687D6E /* CryptoToolsTest.m */; }; B660F6DA1C29868000687D6E /* ExceptionsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B660F6AB1C29868000687D6E /* ExceptionsTest.m */; }; B660F6DB1C29868000687D6E /* FunctionalUtilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B660F6AD1C29868000687D6E /* FunctionalUtilTest.m */; }; - B660F6DF1C29868000687D6E /* QueueTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B660F6B21C29868000687D6E /* QueueTest.m */; }; B660F6E01C29868000687D6E /* UtilTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B660F6B41C29868000687D6E /* UtilTest.m */; }; B660F7171C29988E00687D6E /* OWSContactsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 76EB040918170B33006006FC /* OWSContactsManager.m */; }; B660F7181C29988E00687D6E /* CryptoTools.m in Sources */ = {isa = PBXBuildFile; fileRef = 7038632418F70C0700D4A43F /* CryptoTools.m */; }; @@ -406,6 +409,7 @@ 3400C7971EAFB772008A8584 /* ThreadViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadViewHelper.h; sourceTree = ""; }; 3400C7981EAFB772008A8584 /* ThreadViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadViewHelper.m; sourceTree = ""; }; 340B02B61F9FD31800F9CFEC /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = translations/he.lproj/Localizable.strings; sourceTree = ""; }; + 340B02B91FA0D6C700F9CFEC /* ConversationViewItemTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConversationViewItemTest.m; sourceTree = ""; }; 340CB2221EAC155C0001CAA1 /* ContactsViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactsViewHelper.h; sourceTree = ""; }; 340CB2231EAC155C0001CAA1 /* ContactsViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactsViewHelper.m; sourceTree = ""; }; 340CB2251EAC25820001CAA1 /* UpdateGroupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UpdateGroupViewController.h; sourceTree = ""; }; @@ -494,7 +498,6 @@ 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalsNavigationController.m; sourceTree = ""; }; 34B3F86F1E8DF1700035BE1A /* HomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeViewController.h; sourceTree = ""; }; 34B3F8701E8DF1700035BE1A /* HomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeViewController.m; sourceTree = ""; }; - 34B3F8981E8DF1B90035BE1A /* TSMessageAdapterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageAdapterTest.m; sourceTree = ""; }; 34B3F89A1E8DF3270035BE1A /* BlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockListViewController.h; sourceTree = ""; }; 34B3F89B1E8DF3270035BE1A /* BlockListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlockListViewController.m; sourceTree = ""; }; 34B3F89D1E8DF5490035BE1A /* OWSTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSTableViewController.h; sourceTree = ""; }; @@ -512,6 +515,10 @@ 34C42D631F4734ED0072EC04 /* OWSContactOffersInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactOffersInteraction.m; sourceTree = ""; }; 34C42D641F4734ED0072EC04 /* TSUnreadIndicatorInteraction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSUnreadIndicatorInteraction.h; sourceTree = ""; }; 34C42D651F4734ED0072EC04 /* TSUnreadIndicatorInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSUnreadIndicatorInteraction.m; sourceTree = ""; }; + 34C6B0A51FA0E46F00D35993 /* test-gif.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "test-gif.gif"; sourceTree = ""; }; + 34C6B0A71FA0E46F00D35993 /* test-mp3.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = "test-mp3.mp3"; sourceTree = ""; }; + 34C6B0A81FA0E46F00D35993 /* test-mp4.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "test-mp4.mp4"; sourceTree = ""; }; + 34C6B0AD1FA0E4AA00D35993 /* test-jpg.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "test-jpg.jpg"; sourceTree = ""; }; 34CA1C231F706B5400E51C51 /* NSAttributedString+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+OWS.h"; sourceTree = ""; }; 34CA1C241F706B5400E51C51 /* NSAttributedString+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+OWS.m"; sourceTree = ""; }; 34CA1C261F7156F300E51C51 /* MessageMetadataViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageMetadataViewController.swift; sourceTree = ""; }; @@ -800,8 +807,6 @@ B660F6AB1C29868000687D6E /* ExceptionsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExceptionsTest.m; sourceTree = ""; }; B660F6AC1C29868000687D6E /* FunctionalUtilTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionalUtilTest.h; sourceTree = ""; }; B660F6AD1C29868000687D6E /* FunctionalUtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtilTest.m; sourceTree = ""; }; - B660F6B11C29868000687D6E /* QueueTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QueueTest.h; sourceTree = ""; }; - B660F6B21C29868000687D6E /* QueueTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QueueTest.m; sourceTree = ""; }; B660F6B31C29868000687D6E /* UtilTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UtilTest.h; sourceTree = ""; }; B660F6B41C29868000687D6E /* UtilTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UtilTest.m; sourceTree = ""; }; B661C211198EE2EA00548CA1 /* iOSVersions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iOSVersions.h; path = src/environment/iOSVersions.h; sourceTree = ""; }; @@ -1096,27 +1101,11 @@ 34B3F8951E8DF1B90035BE1A /* ViewControllers */ = { isa = PBXGroup; children = ( - 34B3F8961E8DF1B90035BE1A /* Signals */, + 340B02B91FA0D6C700F9CFEC /* ConversationViewItemTest.m */, ); path = ViewControllers; sourceTree = ""; }; - 34B3F8961E8DF1B90035BE1A /* Signals */ = { - isa = PBXGroup; - children = ( - 34B3F8971E8DF1B90035BE1A /* TSMessageAdapters */, - ); - path = Signals; - sourceTree = ""; - }; - 34B3F8971E8DF1B90035BE1A /* TSMessageAdapters */ = { - isa = PBXGroup; - children = ( - 34B3F8981E8DF1B90035BE1A /* TSMessageAdapterTest.m */, - ); - path = TSMessageAdapters; - sourceTree = ""; - }; 34BECE2C1F7ABCE000D7438D /* GifPicker */ = { isa = PBXGroup; children = ( @@ -1127,6 +1116,17 @@ path = GifPicker; sourceTree = ""; }; + 34C6B0A41FA0E46F00D35993 /* Assets */ = { + isa = PBXGroup; + children = ( + 34C6B0A51FA0E46F00D35993 /* test-gif.gif */, + 34C6B0AD1FA0E4AA00D35993 /* test-jpg.jpg */, + 34C6B0A71FA0E46F00D35993 /* test-mp3.mp3 */, + 34C6B0A81FA0E46F00D35993 /* test-mp4.mp4 */, + ); + path = Assets; + sourceTree = ""; + }; 34CE88E81F3237260098030F /* Profiles */ = { isa = PBXGroup; children = ( @@ -1586,6 +1586,7 @@ B660F66C1C29867F00687D6E /* test */ = { isa = PBXGroup; children = ( + 34C6B0A41FA0E46F00D35993 /* Assets */, B660F6731C29867F00687D6E /* call */, B660F6751C29867F00687D6E /* contact */, 458E38381D6699110094BD24 /* Models */, @@ -1643,8 +1644,6 @@ B660F6AB1C29868000687D6E /* ExceptionsTest.m */, B660F6AC1C29868000687D6E /* FunctionalUtilTest.h */, B660F6AD1C29868000687D6E /* FunctionalUtilTest.m */, - B660F6B11C29868000687D6E /* QueueTest.h */, - B660F6B21C29868000687D6E /* QueueTest.m */, B660F6B31C29868000687D6E /* UtilTest.h */, B660F6B41C29868000687D6E /* UtilTest.m */, 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */, @@ -2010,7 +2009,11 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 34C6B0AE1FA0E4AA00D35993 /* test-jpg.jpg in Resources */, B660F6D41C29868000687D6E /* whisperFake.cer in Resources */, + 34C6B0A91FA0E46F00D35993 /* test-gif.gif in Resources */, + 34C6B0AC1FA0E46F00D35993 /* test-mp4.mp4 in Resources */, + 34C6B0AB1FA0E46F00D35993 /* test-mp3.mp3 in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2415,11 +2418,11 @@ 458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */, 45F659831E1BE77000444429 /* NonCallKitCallUIAdaptee.swift in Sources */, 456AC8351E3A776300A3C7FC /* WeakTimer.swift in Sources */, + 340B02BA1FA0D6C700F9CFEC /* ConversationViewItemTest.m in Sources */, 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */, 452D1EE81DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift in Sources */, 451DE9FE1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */, 45F170AF1E2F0393003FC1F2 /* CallAudioSessionTest.swift in Sources */, - 34B3F8991E8DF1B90035BE1A /* TSMessageAdapterTest.m in Sources */, 456F6E231E24133500FD2210 /* Platform.swift in Sources */, 4539B5871F79348F007141FF /* PushRegistrationManager.swift in Sources */, 4504493A1F45EE7D002D1ADA /* NSString+OWS.m in Sources */, @@ -2468,7 +2471,6 @@ 456F6E201E2411A000FD2210 /* CallService.swift in Sources */, 45A663C61F92EC760027B59E /* GroupTableViewCell.swift in Sources */, 45E615171E8C59100018AD52 /* DisplayableTextFilter.swift in Sources */, - B660F6DF1C29868000687D6E /* QueueTest.m in Sources */, B660F6BB1C29868000687D6E /* OWSContactsManagerTest.m in Sources */, 45A6DAD71EBBF85500893231 /* ReminderView.swift in Sources */, B660F6D21C29868000687D6E /* PushManagerTest.m in Sources */, diff --git a/Signal/test/Assets/test-gif.gif b/Signal/test/Assets/test-gif.gif new file mode 100644 index 000000000..0dcdebc80 Binary files /dev/null and b/Signal/test/Assets/test-gif.gif differ diff --git a/Signal/test/Assets/test-jpg.JPG b/Signal/test/Assets/test-jpg.JPG new file mode 100644 index 000000000..0b82d24e7 Binary files /dev/null and b/Signal/test/Assets/test-jpg.JPG differ diff --git a/Signal/test/Assets/test-mp3.mp3 b/Signal/test/Assets/test-mp3.mp3 new file mode 100644 index 000000000..64a658310 Binary files /dev/null and b/Signal/test/Assets/test-mp3.mp3 differ diff --git a/Signal/test/Assets/test-mp4.mp4 b/Signal/test/Assets/test-mp4.mp4 new file mode 100644 index 000000000..94a7f732a Binary files /dev/null and b/Signal/test/Assets/test-mp4.mp4 differ diff --git a/Signal/test/Models/MesssagesBubblesSizeCalculatorTest.swift b/Signal/test/Models/MesssagesBubblesSizeCalculatorTest.swift index 130d29c99..bfd88d73b 100644 --- a/Signal/test/Models/MesssagesBubblesSizeCalculatorTest.swift +++ b/Signal/test/Models/MesssagesBubblesSizeCalculatorTest.swift @@ -4,16 +4,11 @@ import XCTest -class FakeiPhone6JSQMessagesCollectionViewFlowLayout: JSQMessagesCollectionViewFlowLayout { - // This value was nabbed by inspecting the super class layout.itemSize while debugging the `messageBubbleSizeForMessageData`. - // It requires the view to actually be rendered to get a proper size, so we're baking it in here. - // This will break if we change the layout. - override var itemWidth: CGFloat { return 367 } -} - /** - * This is a brittle test, which will break if our layout changes. It serves mostly as documentation for cases to - * consider when changing the bubble size calculator. Primarly these test cases came out of a bug introduced in iOS10, + * This is a brittle test, which will break if our layout changes. + * + * It serves mostly as documentation for cases to consider when changing the cell measurement logic. + * Primarly these test cases came out of a bug introduced in iOS10, * which prevents us from computing proper bounding box for text that uses the UIEmoji font. * * If one of these tests breaks, it should be OK to update the expected value so long as you've tested the result renders @@ -22,84 +17,88 @@ class FakeiPhone6JSQMessagesCollectionViewFlowLayout: JSQMessagesCollectionViewF */ class MesssagesBubblesSizeCalculatorTest: XCTestCase { - let indexPath = IndexPath() - let layout = FakeiPhone6JSQMessagesCollectionViewFlowLayout() - let calculator = MessagesBubblesSizeCalculator() let thread = TSContactThread()! let contactsManager = OWSContactsManager() - func messageDataForForText(_ text: String?) -> JSQMessageData { + func viewItemForText(_ text: String?) -> ConversationViewItem { let interaction = TSOutgoingMessage(timestamp: 0, in: thread, messageBody: text) interaction.save() - return TSMessageAdapter.messageViewData(with: interaction, in: thread, contactsManager: self.contactsManager) + return ConversationViewItem(tsInteraction:interaction, isGroupThread:false) + } + + func messageBubbleSize(for viewItem: ConversationViewItem) -> CGSize { + viewItem.clearCachedLayoutState() + let viewWidth = 367 + let contentWidth = 367 + return viewItem.cellSize(forViewWidth: Int32(viewWidth), contentWidth:Int32(contentWidth)) } func testHeightForNilMessage() { let text: String? = nil - let messageData = self.messageDataForForText(text) - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText(text) + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(37, actual.height) } func testHeightForShort1LineMessage() { let text = "foo" - let messageData = self.messageDataForForText(text) - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText(text) + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(38, actual.height) } func testHeightForLong1LineMessage() { let text = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 x" - let messageData = self.messageDataForForText(text) - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText(text) + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(38, actual.height) } func testHeightForShort2LineMessage() { let text = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 x 1" - let messageData = self.messageDataForForText(text) - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText(text) + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(59, actual.height) } func testHeightForLong2LineMessage() { let text = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 x 1 2 3 4 5 6 7 8 9 10 11 12 13 14 x" - let messageData = self.messageDataForForText(text) - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText(text) + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(59, actual.height) } func testHeightForiOS10EmojiBug() { - let messageData = self.messageDataForForText("Wunderschönen Guten Morgaaaahhhn 😝 - hast du gut geschlafen ☺️😘") - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText("Wunderschönen Guten Morgaaaahhhn 😝 - hast du gut geschlafen ☺️😘") + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(85.5, actual.height) } func testHeightForiOS10EmojiBug2() { - let messageData = self.messageDataForForText("Test test test test test test test test test test test test 😊❤️❤️") - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText("Test test test test test test test test test test test test 😊❤️❤️") + let actual = messageBubbleSize(for: viewItem) XCTAssertEqual(62, actual.height) } func testHeightForChineseWithEmojiBug() { - let messageData = self.messageDataForForText("一二三四五六七八九十甲乙丙😝戊己庚辛壬圭咖啡牛奶餅乾水果蛋糕") - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText("一二三四五六七八九十甲乙丙😝戊己庚辛壬圭咖啡牛奶餅乾水果蛋糕") + let actual = messageBubbleSize(for: viewItem) // erroneously seeing 69 with the emoji fix in place. XCTAssertEqual(85.5, actual.height) } func testHeightForChineseWithoutEmojiBug() { - let messageData = self.messageDataForForText("一二三四五六七八九十甲乙丙丁戊己庚辛壬圭咖啡牛奶餅乾水果蛋糕") - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText("一二三四五六七八九十甲乙丙丁戊己庚辛壬圭咖啡牛奶餅乾水果蛋糕") + let actual = messageBubbleSize(for: viewItem) // erroneously seeing 69 with the emoji fix in place. XCTAssertEqual(81, actual.height) } func testHeightForiOS10DoubleSpaceNumbersBug() { - let messageData = self.messageDataForForText("12345678901234567890") - let actual = calculator.messageBubbleSize(for: messageData, at: indexPath, with: layout) + let viewItem = self.viewItemForText("12345678901234567890") + let actual = messageBubbleSize(for: viewItem) // erroneously seeing 51 with emoji fix in place. It's the call to "fix string" XCTAssertEqual(59, actual.height) } diff --git a/Signal/test/ViewControllers/ConversationViewItemTest.m b/Signal/test/ViewControllers/ConversationViewItemTest.m new file mode 100644 index 000000000..1009c4d95 --- /dev/null +++ b/Signal/test/ViewControllers/ConversationViewItemTest.m @@ -0,0 +1,347 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "ConversationViewItem.h" +#import +#import +#import +#import +#import + +@interface ConversationViewItem (Testing) + +- (SEL)copyActionSelector; +- (SEL)saveActionSelector; +- (SEL)shareActionSelector; +- (SEL)deleteActionSelector; +- (SEL)metadataActionSelector; + +@end + +@interface ConversationViewItemTest : XCTestCase + +@property (nonatomic, readonly) NSData *fakeAudioData; +@property (nonatomic, readonly) NSData *fakeImageData; + +@end + +@implementation ConversationViewItemTest + +- (NSData *)fakeAudioData +{ + NSString *fakeAudioString = @"QmxhY2tiaXJkIFJhdW0gRG90IE1QMw=="; + return [[NSData alloc] initWithBase64EncodedString:fakeAudioString options:0]; +} + +- (NSData *)fakeVideoData +{ + NSString *fakeVideoString = @"RmFrZSBWaWRlbyBEYXRh"; + return [[NSData alloc] initWithBase64EncodedString:fakeVideoString options:0]; +} + +- (NSData *)fakeImageData +{ + NSString *fakeString = @"RmFrZUltYWdlRGF0YQ=="; + return [[NSData alloc] initWithBase64EncodedString:fakeString options:0]; +} + +- (void)setUp +{ + [super setUp]; +} + +- (void)tearDown +{ + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +// Test canPerformAction + +- (NSString *)fakeTextMessageText +{ + return @"abc"; +} + +- (ConversationViewItem *)textViewItem +{ + TSOutgoingMessage *message = + [[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:self.fakeTextMessageText]; + [message save]; + ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithTSInteraction:message isGroupThread:NO]; + return viewItem; +} + +- (ConversationViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename +{ + OWSAssert(filename.length > 0); + + NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath]; + NSString *filePath = [resourcePath stringByAppendingPathComponent:filename]; + + OWSAssert([[NSFileManager defaultManager] fileExistsAtPath:filePath]); + + TSAttachmentStream *attachment = [[TSAttachmentStream alloc] initWithContentType:mimeType sourceFilename:nil]; + DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:filePath]; + BOOL success = [attachment writeDataSource:dataSource]; + OWSAssert(success); + [attachment save]; + NSMutableArray *attachmentIds = [@[ + attachment.uniqueId, + ] mutableCopy]; + TSOutgoingMessage *message = + [[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:nil attachmentIds:attachmentIds]; + [message save]; + ConversationViewItem *viewItem = [[ConversationViewItem alloc] initWithTSInteraction:message isGroupThread:NO]; + return viewItem; +} + +- (ConversationViewItem *)stillImageViewItem +{ + return [self viewItemWithAttachmentMimetype:@"image/jpeg" filename:@"test-jpg.jpg"]; +} + +- (ConversationViewItem *)animatedImageViewItem +{ + return [self viewItemWithAttachmentMimetype:@"image/gif" filename:@"test-gif.gif"]; +} + +- (ConversationViewItem *)videoViewItem +{ + return [self viewItemWithAttachmentMimetype:@"video/mp4" filename:@"test-mp4.mp4"]; +} + +- (ConversationViewItem *)audioViewItem +{ + return [self viewItemWithAttachmentMimetype:@"audio/mp3" filename:@"test-mp3.mp3"]; +} + +- (void)testCanPerformEditingActionWithNonMediaMessage +{ + ConversationViewItem *viewItem = self.textViewItem; + + XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]); + XCTAssertFalse([viewItem canPerformAction:viewItem.saveActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]); + XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]); +} + +- (void)testCanPerformEditingActionWithPhotoMessage +{ + ConversationViewItem *viewItem = self.stillImageViewItem; + + XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.saveActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]); + XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]); +} + +- (void)testCanPerformEditingActionWithAnimatedMessage +{ + ConversationViewItem *viewItem = self.animatedImageViewItem; + + XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.saveActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]); + XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]); +} + +- (void)testCanPerformEditingActionWithVideoMessage +{ + ConversationViewItem *viewItem = self.videoViewItem; + + XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.saveActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]); + XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]); +} + +- (void)testCanPerformEditingActionWithAudioMessage +{ + ConversationViewItem *viewItem = self.audioViewItem; + + XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]); + XCTAssertFalse([viewItem canPerformAction:viewItem.saveActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]); + XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]); + XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]); +} + +// Test Delete + +- (void)testPerformDeleteEditingActionWithNonMediaMessage +{ + ConversationViewItem *viewItem = self.textViewItem; + + XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + [viewItem deleteAction]; + XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); +} + +- (void)testPerformDeleteActionWithPhotoMessage +{ + ConversationViewItem *viewItem = self.stillImageViewItem; + + XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); + NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; + XCTAssertNotNil(attachmentId); + TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; + XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); + TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; + NSString *_Nullable filePath = attachmentStream.filePath; + XCTAssertNotNil(filePath); + + XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); + [viewItem deleteAction]; + XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); +} + +- (void)testPerformDeleteEditingActionWithAnimatedMessage +{ + ConversationViewItem *viewItem = self.animatedImageViewItem; + + XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); + NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; + XCTAssertNotNil(attachmentId); + TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; + XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); + TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; + NSString *_Nullable filePath = attachmentStream.filePath; + XCTAssertNotNil(filePath); + + XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); + [viewItem deleteAction]; + XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); +} + +- (void)testPerformDeleteEditingActionWithVideoMessage +{ + ConversationViewItem *viewItem = self.videoViewItem; + + XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); + NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; + XCTAssertNotNil(attachmentId); + TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; + XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); + TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; + NSString *_Nullable filePath = attachmentStream.filePath; + XCTAssertNotNil(filePath); + + XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); + [viewItem deleteAction]; + XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); +} + +- (void)testPerformDeleteEditingActionWithAudioMessage +{ + ConversationViewItem *viewItem = self.audioViewItem; + + XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count); + NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject; + XCTAssertNotNil(attachmentId); + TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId]; + XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]); + TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment; + NSString *_Nullable filePath = attachmentStream.filePath; + XCTAssertNotNil(filePath); + + XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]); + [viewItem deleteAction]; + XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]); + XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]); + XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]); +} + +// Test Copy + +- (void)testPerformCopyEditingActionWithNonMediaMessage +{ + // Reset the pasteboard. + UIPasteboard.generalPasteboard.items = @[]; + XCTAssertNil(UIPasteboard.generalPasteboard.string); + + ConversationViewItem *viewItem = self.textViewItem; + [viewItem copyAction]; + XCTAssertEqualObjects(self.fakeTextMessageText, UIPasteboard.generalPasteboard.string); +} + +- (void)testPerformCopyEditingActionWithStillImageMessage +{ + // Reset the pasteboard. + UIPasteboard.generalPasteboard.items = @[]; + XCTAssertNil(UIPasteboard.generalPasteboard.image); + XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]); + + ConversationViewItem *viewItem = self.stillImageViewItem; + [viewItem copyAction]; + NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]; + XCTAssertTrue(copiedData.length > 0); +} + +- (void)testPerformCopyEditingActionWithAnimatedImageMessage +{ + // Reset the pasteboard. + UIPasteboard.generalPasteboard.items = @[]; + XCTAssertNil(UIPasteboard.generalPasteboard.image); + XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]); + + ConversationViewItem *viewItem = self.animatedImageViewItem; + [viewItem copyAction]; + NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]; + XCTAssertTrue(copiedData.length > 0); +} + +- (void)testPerformCopyEditingActionWithVideoMessage +{ + // Reset the pasteboard. + UIPasteboard.generalPasteboard.items = @[]; + XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]); + + ConversationViewItem *viewItem = self.videoViewItem; + [viewItem copyAction]; + NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]; + XCTAssertTrue(copiedData.length > 0); +} + +- (void)testPerformCopyEditingActionWithMp3AudioMessage +{ + // Reset the pasteboard. + UIPasteboard.generalPasteboard.items = @[]; + XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]); + + ConversationViewItem *viewItem = self.audioViewItem; + [viewItem copyAction]; + NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]; + XCTAssertTrue(copiedData.length > 0); +} + +- (void)unknownAction:(id)sender +{ + // It's easier to create this stub method than to suppress the "unknown selector" build warnings. +} + +@end diff --git a/Signal/test/ViewControllers/Signals/TSMessageAdapters/TSMessageAdapterTest.m b/Signal/test/ViewControllers/Signals/TSMessageAdapters/TSMessageAdapterTest.m deleted file mode 100644 index 8c63cda63..000000000 --- a/Signal/test/ViewControllers/Signals/TSMessageAdapters/TSMessageAdapterTest.m +++ /dev/null @@ -1,335 +0,0 @@ -// -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. -// - -#import "TSAttachmentStream.h" -#import "TSOutgoingMessage.h" -#import -#import - -@interface TSMessageAdapter (Testing) - -// expose some private setters for ease of testing setup -@property (nonatomic, retain) NSString *messageBody; -@property JSQMediaItem *mediaItem; - -@end - -@interface TSMessageAdapterTest : XCTestCase - -@property TSMessageAdapter *messageAdapter; -@property TSOutgoingMessage *message; -@property (readonly) NSData *fakeAudioData; -@property (readonly) NSData *fakeImageData; - -@end - -@implementation TSMessageAdapterTest - -- (NSData *)fakeAudioData -{ - NSString *fakeAudioString = @"QmxhY2tiaXJkIFJhdW0gRG90IE1QMw=="; - return [[NSData alloc] initWithBase64EncodedString:fakeAudioString options:0]; -} - -- (NSData *)fakeVideoData -{ - NSString *fakeVideoString = @"RmFrZSBWaWRlbyBEYXRh"; - return [[NSData alloc] initWithBase64EncodedString:fakeVideoString options:0]; -} - -- (NSData *)fakeImageData -{ - NSString *fakeString = @"RmFrZUltYWdlRGF0YQ=="; - return [[NSData alloc] initWithBase64EncodedString:fakeString options:0]; -} - -- (void)setUp -{ - [super setUp]; - - self.message = [[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:nil]; - [self.message save]; - - self.messageAdapter = [TSMessageAdapter new]; - self.messageAdapter.interaction = self.message; -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -// Test canPerformAction - -- (void)testCanPerformEditingActionWithNonMediaMessage -{ - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(copy:)]); - - XCTAssertFalse([self.messageAdapter canPerformEditingAction:NSSelectorFromString(@"save:")]); - - //e.g. any other unsupported action - XCTAssertFalse([self.messageAdapter canPerformEditingAction:@selector(paste:)]); -} - -- (void)testCanPerformEditingActionWithPhotoMessage -{ - self.messageAdapter.mediaItem = [[TSPhotoAdapter alloc] init]; - - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(copy:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:NSSelectorFromString(@"save:")]); - - // e.g. any other unsupported action - XCTAssertFalse([self.messageAdapter canPerformEditingAction:@selector(paste:)]); -} - -- (void)testCanPerformEditingActionWithAnimatedMessage -{ - self.messageAdapter.mediaItem = [[TSAnimatedAdapter alloc] init]; - - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(copy:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:NSSelectorFromString(@"save:")]); - - // e.g. any other unsupported action - XCTAssertFalse([self.messageAdapter canPerformEditingAction:@selector(paste:)]); -} - -- (void)testCanPerformEditingActionWithVideoMessage -{ - TSAttachmentStream *videoAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"video/mp4" sourceFilename:nil]; - - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:NO]; - - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(copy:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:NSSelectorFromString(@"save:")]); - - // e.g. any other unsupported action - XCTAssertFalse([self.messageAdapter canPerformEditingAction:@selector(paste:)]); -} - -- (void)testCanPerformEditingActionWithAudioMessage -{ - TSAttachmentStream *audioAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" sourceFilename:nil]; - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO]; - - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(delete:)]); - XCTAssertTrue([self.messageAdapter canPerformEditingAction:@selector(copy:)]); - - //e.g. Can't save an audio attachment at this time. - XCTAssertFalse([self.messageAdapter canPerformEditingAction:NSSelectorFromString(@"save:")]); - - //e.g. any other unsupported action - XCTAssertFalse([self.messageAdapter canPerformEditingAction:@selector(paste:)]); -} - -// Test Delete - -- (void)testPerformDeleteEditingActionWithNonMediaMessage -{ - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - [self.messageAdapter performEditingAction:@selector(delete:)]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); -} - -- (void)testPerformDeleteActionWithPhotoMessage -{ - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - - self.messageAdapter.mediaItem = [[TSPhotoAdapter alloc] init]; - [self.messageAdapter performEditingAction:@selector(delete:)]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - // TODO assert files are deleted -} - -- (void)testPerformDeleteEditingActionWithAnimatedMessage -{ - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - - self.messageAdapter.mediaItem = [[TSAnimatedAdapter alloc] init]; - [self.messageAdapter performEditingAction:@selector(delete:)]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - // TODO assert files are deleted -} - -- (void)testPerformDeleteEditingActionWithVideoMessage -{ - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - - NSError *error; - TSAttachmentStream *videoAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"video/mp4" sourceFilename:nil]; - [videoAttachment writeData:[NSData new] error:&error]; - [videoAttachment save]; - - [self.message.attachmentIds addObject:videoAttachment.uniqueId]; - [self.message save]; - - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:NO]; - - // Sanity Check - XCTAssert([[NSFileManager defaultManager] fileExistsAtPath:videoAttachment.filePath]); - - [self.messageAdapter performEditingAction:@selector(delete:)]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:videoAttachment.filePath]); -} - -- (void)testPerformDeleteEditingActionWithAudioMessage -{ - XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - - NSError *error; - TSAttachmentStream *audioAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" sourceFilename:nil]; - [audioAttachment writeData:[NSData new] error:&error]; - [audioAttachment save]; - - [self.message.attachmentIds addObject:audioAttachment.uniqueId]; - [self.message save]; - - // Sanity Check - XCTAssertNil(error); - XCTAssert([[NSFileManager defaultManager] fileExistsAtPath:audioAttachment.filePath]); - - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO]; - - [self.messageAdapter performEditingAction:@selector(delete:)]; - XCTAssertNil([TSMessage fetchObjectWithUniqueID:self.message.uniqueId]); - XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:audioAttachment.filePath]); -} - -// Test Copy - -- (void)testPerformCopyEditingActionWithNonMediaMessage -{ - self.messageAdapter.messageBody = @"My message text"; - [self.messageAdapter performEditingAction:@selector(copy:)]; - XCTAssertEqualObjects(@"My message text", UIPasteboard.generalPasteboard.string); -} - -- (void)testPerformCopyEditingActionWithPhotoMessage -{ - // reset the paste board for clean slate test - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil(UIPasteboard.generalPasteboard.image); - - NSError *error; - TSAttachmentStream *attachment = [[TSAttachmentStream alloc] initWithContentType:@"image/jpeg" sourceFilename:nil]; - [attachment writeData:self.fakeAudioData error:&error]; - [attachment save]; - - // Sanity Check - XCTAssertNil(error); - XCTAssert([[NSFileManager defaultManager] fileExistsAtPath:attachment.filePath]); - - [self.message.attachmentIds addObject:attachment.uniqueId]; - [self.message save]; - - TSPhotoAdapter *photoAdapter = [[TSPhotoAdapter alloc] initWithAttachment:attachment incoming:NO]; - // assign random image, since photoAdapter expects an image. - photoAdapter.image = [UIImage imageNamed:@"savephoto"]; - self.messageAdapter.mediaItem = photoAdapter; - - [self.messageAdapter performEditingAction:@selector(copy:)]; - - NSData *copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]; - XCTAssertEqualObjects(self.fakeAudioData, copiedData); -} - -- (void)testPerformCopyEditingActionWithVideoMessage -{ - // reset the paste board for clean slate test - UIPasteboard.generalPasteboard.items = @[]; - - NSError *error; - TSAttachmentStream *videoAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"video/mp4" sourceFilename:nil]; - [videoAttachment writeData:self.fakeVideoData error:&error]; - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:videoAttachment incoming:YES]; - - [self.messageAdapter performEditingAction:@selector(copy:)]; - - NSData *copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]; - XCTAssertEqualObjects(self.fakeVideoData, copiedData); -} - -- (void)testPerformCopyEditingActionWithMp3AudioMessage -{ - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]); - - NSError *error; - TSAttachmentStream *audioAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"audio/mp3" sourceFilename:nil]; - [audioAttachment writeData:self.fakeAudioData error:&error]; - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO]; - - [self.messageAdapter performEditingAction:@selector(copy:)]; - XCTAssertEqualObjects(self.fakeAudioData, [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]); -} - -- (void)testPerformCopyEditingActionWithM4aAudioMessage -{ - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4Audio]); - - NSError *error; - TSAttachmentStream *audioAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"audio/x-m4a" sourceFilename:nil]; - [audioAttachment writeData:self.fakeAudioData error:&error]; - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO]; - - [self.messageAdapter performEditingAction:@selector(copy:)]; - XCTAssertEqualObjects(self.fakeAudioData, [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4Audio]); -} - -- (void)testPerformCopyEditingActionWithGenericAudioMessage -{ - UIPasteboard.generalPasteboard.items = @[]; - XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeAudio]); - - NSError *error; - TSAttachmentStream *audioAttachment = - [[TSAttachmentStream alloc] initWithContentType:@"audio/wav" sourceFilename:nil]; - [audioAttachment writeData:self.fakeAudioData error:&error]; - self.messageAdapter.mediaItem = [[TSVideoAttachmentAdapter alloc] initWithAttachment:audioAttachment incoming:NO]; - - [self.messageAdapter performEditingAction:@selector(copy:)]; - XCTAssertEqualObjects(self.fakeAudioData, [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeAudio]); -} - -// TODO - We don't currenlty have a good way of testing "copy of an animated message attachment" -// We need an attachment with some NSData, which requires getting into the crypto layer, -// which is outside of my realm. -// -// Since you can't currently PASTE images into our version of JSQMessageViewController, I tested this by pasting -// into native Messages client, and verifying the result was animated. -// -//- (void)testPerformCopyActionWithAnimatedMessage -//{ -// // reset the paste board for clean slate test -// UIPasteboard.generalPasteboard.items = @[]; -// XCTAssertNil(UIPasteboard.generalPasteboard.image); -// -// // "some-animated-gif" doesn't exist yet -// NSData *imageData = [[NSData alloc] initWithContentsOfFile:@"some-animated-gif"]; -// //TODO build attachment with imageData -// TSAttachmentStream animatedAttachement = [[TSAttachmentStream alloc] initWithIdentifier:@"test-animated-attachment-id" data:imageDatq key:@"TODO" contentType:@"image/gif"]; -// TSAnimatedAdapter *animatedAdapter = [[TSAnimatedAdapter alloc] initWithAttachment:animatedAttachment]; -// animatedAdapter.image = image; -// self.messageAdapter.mediaItem = animatedAdapter; -// [self.messageAdapter performEditingAction:@selector(copy:)]; -// -// // TODO XCTAssert that image is copied as a GIF (e.g. not convereted to a PNG, etc.) -// // We want to be sure that we can copy/paste an animated GIF from -// // one thread to the other, and ensure it's still animated. -//} - -@end diff --git a/Signal/test/util/QueueTest.h b/Signal/test/util/QueueTest.h deleted file mode 100644 index 55ddd69d8..000000000 --- a/Signal/test/util/QueueTest.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface QueueTest : XCTestCase - -@end diff --git a/Signal/test/util/QueueTest.m b/Signal/test/util/QueueTest.m deleted file mode 100644 index 98c49ba4e..000000000 --- a/Signal/test/util/QueueTest.m +++ /dev/null @@ -1,31 +0,0 @@ -#import "Queue.h" -#import "QueueTest.h" -#import "TestUtil.h" - -@implementation QueueTest - -- (void)testQueue { - Queue *q = [Queue new]; - test(q.count == 0); - testThrows(q.peek); - testThrows([q dequeue]); - - [q enqueue:@5]; - test(q.count == 1); - test([q.peek isEqualToNumber:@5]); - - [q enqueue:@23]; - test(q.count == 2); - test([q.peek isEqualToNumber:@5]); - - test([[q dequeue] isEqualToNumber:@5]); - test(q.count == 1); - test([q.peek isEqualToNumber:@23]); - - test([[q dequeue] isEqualToNumber:@23]); - test(q.count == 0); - testThrows(q.peek); - testThrows([q dequeue]); -} - -@end diff --git a/SignalServiceKit/src/Util/MIMETypeUtil.m b/SignalServiceKit/src/Util/MIMETypeUtil.m index 340d1082e..68452e2c8 100644 --- a/SignalServiceKit/src/Util/MIMETypeUtil.m +++ b/SignalServiceKit/src/Util/MIMETypeUtil.m @@ -3,10 +3,13 @@ // #import "MIMETypeUtil.h" + #if TARGET_OS_IPHONE #import + #else #import + #endif NS_ASSUME_NONNULL_BEGIN