DisplayableTextFilterTest.swift 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. //
  2. // Copyright (c) 2019 Open Whisper Systems. All rights reserved.
  3. //
  4. import XCTest
  5. @testable import Signal
  6. @testable import SignalMessaging
  7. class DisplayableTextTest: SignalBaseTest {
  8. override func setUp() {
  9. super.setUp()
  10. // Put setup code here. This method is called before the invocation of each test method in the class.
  11. }
  12. override func tearDown() {
  13. // Put teardown code here. This method is called after the invocation of each test method in the class.
  14. super.tearDown()
  15. }
  16. func testDisplayableText() {
  17. // show plain text
  18. let boringText = "boring text"
  19. XCTAssertEqual(boringText, boringText.filterStringForDisplay())
  20. // show high byte emojis
  21. let emojiText = "🇹🇹🌼🇹🇹🌼🇹🇹"
  22. XCTAssertEqual(emojiText, emojiText.filterStringForDisplay())
  23. // show normal diacritic usage
  24. let diacriticalText = "Příliš žluťoučký kůň úpěl ďábelské ódy."
  25. XCTAssertEqual(diacriticalText, diacriticalText.filterStringForDisplay())
  26. // filter excessive diacritics
  27. XCTAssertEqual("HAVING TROUBLE READING TEXT?", "H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".filterStringForDisplay() )
  28. XCTAssertEqual("LGO!", "L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".filterStringForDisplay())
  29. }
  30. func testGlyphCount() {
  31. // Plain text
  32. XCTAssertEqual("boring text".glyphCount, 11)
  33. // Emojis
  34. XCTAssertEqual("🇹🇹🌼🇹🇹🌼🇹🇹".glyphCount, 5)
  35. XCTAssertEqual("🇹🇹".glyphCount, 1)
  36. XCTAssertEqual("🇹🇹 ".glyphCount, 2)
  37. XCTAssertEqual("👌🏽👌🏾👌🏿".glyphCount, 3)
  38. XCTAssertEqual("😍".glyphCount, 1)
  39. XCTAssertEqual("👩🏽".glyphCount, 1)
  40. XCTAssertEqual("👾🙇💁🙅🙆🙋🙎🙍".glyphCount, 8)
  41. XCTAssertEqual("🐵🙈🙉🙊".glyphCount, 4)
  42. XCTAssertEqual("❤️💔💌💕💞💓💗💖💘💝💟💜💛💚💙".glyphCount, 15)
  43. XCTAssertEqual("✋🏿💪🏿👐🏿🙌🏿👏🏿🙏🏿".glyphCount, 6)
  44. XCTAssertEqual("🚾🆒🆓🆕🆖🆗🆙🏧".glyphCount, 8)
  45. XCTAssertEqual("0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟".glyphCount, 11)
  46. XCTAssertEqual("🇺🇸🇷🇺🇦🇫🇦🇲".glyphCount, 4)
  47. XCTAssertEqual("🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸".glyphCount, 7)
  48. XCTAssertEqual("🇺🇸🇷🇺🇸🇦🇫🇦🇲".glyphCount, 5)
  49. XCTAssertEqual("🇺🇸🇷🇺🇸🇦".glyphCount, 3)
  50. XCTAssertEqual("123".glyphCount, 3)
  51. // Normal diacritic usage
  52. XCTAssertEqual("Příliš žluťoučký kůň úpěl ďábelské ódy.".glyphCount, 39)
  53. // Excessive diacritics
  54. // some insignificant discrepencies across iOS versions
  55. if #available(iOS 11, *) {
  56. XCTAssertEqual("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".glyphCount, 115)
  57. } else {
  58. XCTAssertEqual("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".glyphCount, 109)
  59. }
  60. XCTAssertEqual("L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".glyphCount, 43)
  61. }
  62. func testContainsOnlyEmoji() {
  63. // Plain text
  64. XCTAssertFalse("boring text".containsOnlyEmoji)
  65. // Emojis
  66. XCTAssertTrue("🇹🇹🌼🇹🇹🌼🇹🇹".containsOnlyEmoji)
  67. XCTAssertTrue("🇹🇹".containsOnlyEmoji)
  68. XCTAssertFalse("🇹🇹 ".containsOnlyEmoji)
  69. XCTAssertTrue("👌🏽👌🏾👌🏿".containsOnlyEmoji)
  70. XCTAssertTrue("😍".containsOnlyEmoji)
  71. XCTAssertTrue("👩🏽".containsOnlyEmoji)
  72. XCTAssertTrue("👾🙇💁🙅🙆🙋🙎🙍".containsOnlyEmoji)
  73. XCTAssertTrue("🐵🙈🙉🙊".containsOnlyEmoji)
  74. XCTAssertTrue("❤️💔💌💕💞💓💗💖💘💝💟💜💛💚💙".containsOnlyEmoji)
  75. XCTAssertTrue("✋🏿💪🏿👐🏿🙌🏿👏🏿🙏🏿".containsOnlyEmoji)
  76. XCTAssertTrue("🚾🆒🆓🆕🆖🆗🆙🏧".containsOnlyEmoji)
  77. XCTAssertFalse("0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣🔟".containsOnlyEmoji)
  78. XCTAssertTrue("🇺🇸🇷🇺🇦🇫🇦🇲".containsOnlyEmoji)
  79. XCTAssertFalse("🇺🇸🇷🇺🇸 🇦🇫🇦🇲🇸".containsOnlyEmoji)
  80. XCTAssertTrue("🇺🇸🇷🇺🇸🇦🇫🇦🇲".containsOnlyEmoji)
  81. XCTAssertTrue("🇺🇸🇷🇺🇸🇦".containsOnlyEmoji)
  82. // Unicode standard doesn't consider these to be Emoji.
  83. XCTAssertFalse("123".containsOnlyEmoji)
  84. // Normal diacritic usage
  85. XCTAssertFalse("Příliš žluťoučký kůň úpěl ďábelské ódy.".containsOnlyEmoji)
  86. // Excessive diacritics
  87. XCTAssertFalse("H҉̸̧͘͠A͢͞V̛̛I̴̸N͏̕͏G҉̵͜͏͢ ̧̧́T̶̛͘͡R̸̵̨̢̀O̷̡U͡҉B̶̛͢͞L̸̸͘͢͟É̸ ̸̛͘͏R͟È͠͞A̸͝Ḑ̕͘͜I̵͘҉͜͞N̷̡̢͠G̴͘͠ ͟͞T͏̢́͡È̀X̕҉̢̀T̢͠?̕͏̢͘͢".containsOnlyEmoji)
  88. XCTAssertFalse("L̷̳͔̲͝Ģ̵̮̯̤̩̙͍̬̟͉̹̘̹͍͈̮̦̰̣͟͝O̶̴̮̻̮̗͘͡!̴̷̟͓͓".containsOnlyEmoji)
  89. }
  90. func test_shouldAllowLinkification() {
  91. func assertLinkifies(_ text: String, file: StaticString = #file, line: UInt = #line) {
  92. let displayableText = DisplayableText.displayableText(text)
  93. XCTAssert(displayableText.shouldAllowLinkification, "was not linkifiable text: \(text)", file: file, line: line)
  94. }
  95. func assertNotLinkifies(_ text: String, file: StaticString = #file, line: UInt = #line) {
  96. let displayableText = DisplayableText.displayableText(text)
  97. XCTAssertFalse(displayableText.shouldAllowLinkification, "was linkifiable text: \(text)", file: file, line: line)
  98. }
  99. // some basic happy paths
  100. assertLinkifies("foo google.com")
  101. assertLinkifies("google.com/foo")
  102. assertLinkifies("blah google.com/foo")
  103. assertLinkifies("foo http://google.com")
  104. assertLinkifies("foo https://google.com")
  105. // cyrillic host with ascii tld
  106. assertNotLinkifies("foo http://asĸ.com")
  107. assertNotLinkifies("http://asĸ.com")
  108. assertNotLinkifies("asĸ.com")
  109. // Mixed latin and cyrillic text, but it's not a link
  110. // (nothing to linkify, but there's nothing illegal here)
  111. assertLinkifies("asĸ")
  112. // Cyrillic host with cyrillic TLD
  113. assertLinkifies("http://кц.рф")
  114. assertLinkifies("https://кц.рф")
  115. assertLinkifies("кц.рф")
  116. assertLinkifies("https://кц.рф/foo")
  117. assertLinkifies("https://кц.рф/кц")
  118. assertLinkifies("https://кц.рф/кцfoo")
  119. // ascii text outside of the link, with cyrillic host + cyrillic domain
  120. assertLinkifies("some text: кц.рф")
  121. // Mixed ascii/cyrillic text outside of the link, with cyrillic host + cyrillic domain
  122. assertLinkifies("asĸ кц.рф")
  123. assertLinkifies("google.com")
  124. assertLinkifies("foo.google.com")
  125. assertLinkifies("https://foo.google.com")
  126. assertLinkifies("https://foo.google.com/some/path.html")
  127. assertNotLinkifies("asĸ.com")
  128. assertNotLinkifies("https://кц.cфm")
  129. assertNotLinkifies("https://google.cфm")
  130. assertLinkifies("кц.рф")
  131. assertLinkifies("кц.рф/some/path")
  132. assertLinkifies("https://кц.рф/some/path")
  133. assertNotLinkifies("http://foo.кц.рф")
  134. }
  135. }