SwiftyMarkdownCharacterTests.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. //
  2. // SwiftyMarkdownCharacterTests.swift
  3. // SwiftyMarkdownTests
  4. //
  5. // Created by Simon Fairbairn on 17/12/2019.
  6. // Copyright © 2019 Voyage Travel Apps. All rights reserved.
  7. //
  8. @testable import SwiftyMarkdown
  9. import XCTest
  10. class SwiftyMarkdownStylingTests: SwiftyMarkdownCharacterTests {
  11. func testIsolatedCase() {
  12. challenge = TokenTest(input: "A string with a **bold** word", output: "A string with a bold word", tokens: [
  13. Token(type: .string, inputString: "A string with a ", characterStyles: []),
  14. Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold]),
  15. Token(type: .string, inputString: " word", characterStyles: [])
  16. ])
  17. results = self.attempt(challenge)
  18. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  19. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  20. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  21. XCTAssertEqual(results.attributedString.string, challenge.output)
  22. return
  23. challenge = TokenTest(input: "An *\\*italic\\** [referenced link][link]", output: "An *italic* referenced link", tokens: [
  24. Token(type: .string, inputString: "An ", characterStyles: []),
  25. Token(type: .string, inputString: "*italic*", characterStyles: [CharacterStyle.italic]),
  26. Token(type: .string, inputString: " ", characterStyles: []),
  27. Token(type: .string, inputString: "referenced link", characterStyles: [CharacterStyle.link])
  28. ])
  29. rules = [
  30. CharacterRule(openTag: "*", escapeCharacter: "\\", styles: [1 : [CharacterStyle.italic], 2 : [.bold], 3 : [.italic, .bold]], minTags: 1, maxTags: 3),
  31. CharacterRule(openTag: "[", intermediateTag: "](", closingTag: ")", escapeCharacter: "\\", styles: [1 : [CharacterStyle.link]], minTags: 1, maxTags: 1),
  32. CharacterRule(openTag: "[", intermediateTag: "][", closingTag: "]", escapeCharacter: "\\", styles: [1 : [CharacterStyle.link]], minTags: 1, maxTags: 1)
  33. ]
  34. results = self.attempt(challenge, rules: rules)
  35. XCTAssertEqual(results.stringTokens.count, challenge.tokens.count)
  36. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  37. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  38. if results.links.count == 1 {
  39. XCTAssertEqual(results.links[0].metadataString, "https://www.neverendingvoyage.com/")
  40. } else {
  41. XCTFail("Incorrect link count. Expecting 1, found \(results.links.count)")
  42. }
  43. }
  44. func testThatBoldTraitsAreRecognised() {
  45. challenge = TokenTest(input: "**A bold string**", output: "A bold string", tokens: [
  46. Token(type: .string, inputString: "A bold string", characterStyles: [CharacterStyle.bold])
  47. ])
  48. results = self.attempt(challenge)
  49. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  50. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  51. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  52. XCTAssertEqual(results.attributedString.string, challenge.output)
  53. challenge = TokenTest(input: "A string with a **bold** word", output: "A string with a bold word", tokens: [
  54. Token(type: .string, inputString: "A string with a ", characterStyles: []),
  55. Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold]),
  56. Token(type: .string, inputString: " word", characterStyles: [])
  57. ])
  58. results = self.attempt(challenge)
  59. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  60. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  61. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  62. XCTAssertEqual(results.attributedString.string, challenge.output)
  63. challenge = TokenTest(input: "\\*\\*A normal string\\*\\*", output: "**A normal string**", tokens: [
  64. Token(type: .string, inputString: "**A normal string**", characterStyles: [])
  65. ])
  66. results = self.attempt(challenge)
  67. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  68. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  69. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  70. XCTAssertEqual(results.attributedString.string, challenge.output)
  71. challenge = TokenTest(input: "\\\\*\\*A normal \\\\ string\\*\\*", output: "\\**A normal \\\\ string**", tokens: [
  72. Token(type: .string, inputString: "\\**A normal \\\\ string**", characterStyles: [])
  73. ])
  74. results = self.attempt(challenge)
  75. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  76. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  77. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  78. XCTAssertEqual(results.attributedString.string, challenge.output)
  79. challenge = TokenTest(input: "A string with double \\*\\*escaped\\*\\* asterisks", output: "A string with double **escaped** asterisks", tokens: [
  80. Token(type: .string, inputString: "A string with double **escaped** asterisks", characterStyles: [])
  81. ])
  82. results = self.attempt(challenge)
  83. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  84. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  85. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  86. XCTAssertEqual(results.attributedString.string, challenge.output)
  87. challenge = TokenTest(input: "\\**One escaped, one not at either end\\**", output: "*One escaped, one not at either end*", tokens: [
  88. Token(type: .string, inputString: "*", characterStyles: []),
  89. Token(type: .string, inputString: "One escaped, one not at either end*", characterStyles: [CharacterStyle.italic]),
  90. ])
  91. results = self.attempt(challenge)
  92. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  93. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  94. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  95. XCTAssertEqual(results.attributedString.string, challenge.output)
  96. challenge = TokenTest(input: "A string with one \\**escaped\\** asterisk, one not at either end", output: "A string with one *escaped* asterisk, one not at either end", tokens: [
  97. Token(type: .string, inputString: "A string with one *", characterStyles: []),
  98. Token(type: .string, inputString: "escaped*", characterStyles: [CharacterStyle.italic]),
  99. Token(type: .string, inputString: " asterisk, one not at either end", characterStyles: [])
  100. ])
  101. results = self.attempt(challenge)
  102. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  103. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  104. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  105. XCTAssertEqual(results.attributedString.string, challenge.output)
  106. }
  107. func testThatCodeTraitsAreRecognised() {
  108. challenge = TokenTest(input: "`Code (**should** not process internal tags)`", output: "Code (**should** not process internal tags)", tokens: [
  109. Token(type: .string, inputString: "Code (**should** not process internal tags) ", characterStyles: [CharacterStyle.code])
  110. ])
  111. results = self.attempt(challenge)
  112. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  113. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  114. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  115. XCTAssertEqual(results.attributedString.string, challenge.output)
  116. challenge = TokenTest(input: "A string with `code` (should not be indented)", output: "A string with code (should not be indented)", tokens : [
  117. Token(type: .string, inputString: "A string with ", characterStyles: []),
  118. Token(type: .string, inputString: "code", characterStyles: [CharacterStyle.code]),
  119. Token(type: .string, inputString: " (should not be indented)", characterStyles: [])
  120. ])
  121. results = self.attempt(challenge)
  122. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  123. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  124. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  125. XCTAssertEqual(results.attributedString.string, challenge.output)
  126. challenge = TokenTest(input: "`A code string` with multiple `code` `instances`", output: "A code string with multiple code instances", tokens : [
  127. Token(type: .string, inputString: "A code string", characterStyles: [CharacterStyle.code]),
  128. Token(type: .string, inputString: " with multiple ", characterStyles: []),
  129. Token(type: .string, inputString: "code", characterStyles: [CharacterStyle.code]),
  130. Token(type: .string, inputString: " ", characterStyles: []),
  131. Token(type: .string, inputString: "instances", characterStyles: [CharacterStyle.code])
  132. ])
  133. results = self.attempt(challenge)
  134. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  135. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  136. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  137. XCTAssertEqual(results.attributedString.string, challenge.output)
  138. challenge = TokenTest(input: "\\`A normal string\\`", output: "`A normal string`", tokens: [
  139. Token(type: .string, inputString: "`A normal string`", characterStyles: [])
  140. ])
  141. results = self.attempt(challenge)
  142. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  143. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  144. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  145. XCTAssertEqual(results.attributedString.string, challenge.output)
  146. challenge = TokenTest(input: "A string with \\`escaped\\` backticks", output: "A string with `escaped` backticks", tokens: [
  147. Token(type: .string, inputString: "A string with `escaped` backticks", characterStyles: [])
  148. ])
  149. results = self.attempt(challenge)
  150. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  151. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  152. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  153. XCTAssertEqual(results.attributedString.string, challenge.output)
  154. challenge = TokenTest(input: "A lonely backtick: `", output: "A lonely backtick: `", tokens: [
  155. Token(type: .string, inputString: "A lonely backtick: `", characterStyles: [])
  156. ])
  157. results = self.attempt(challenge)
  158. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  159. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  160. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  161. XCTAssertEqual(results.attributedString.string, challenge.output)
  162. challenge = TokenTest(input: "Two backticks followed by a full stop ``.", output: "Two backticks followed by a full stop ``.", tokens: [
  163. Token(type: .string, inputString: "Two backticks followed by a full stop ``.", characterStyles: [])
  164. ])
  165. results = self.attempt(challenge)
  166. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  167. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  168. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  169. XCTAssertEqual(results.attributedString.string, challenge.output)
  170. }
  171. func testThatItalicTraitsAreParsedCorrectly() {
  172. challenge = TokenTest(input: "*An italicised string*", output: "An italicised string", tokens : [
  173. Token(type: .string, inputString: "An italicised string", characterStyles: [CharacterStyle.italic])
  174. ])
  175. results = self.attempt(challenge)
  176. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  177. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  178. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  179. XCTAssertEqual(results.attributedString.string, challenge.output)
  180. challenge = TokenTest(input: "A string with *italicised* text", output: "A string with italicised text", tokens : [
  181. Token(type: .string, inputString: "A string with ", characterStyles: []),
  182. Token(type: .string, inputString: "italicised", characterStyles: [CharacterStyle.italic]),
  183. Token(type: .string, inputString: " text", characterStyles: [])
  184. ])
  185. results = self.attempt(challenge)
  186. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  187. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  188. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  189. XCTAssertEqual(results.attributedString.string, challenge.output)
  190. challenge = TokenTest(input: "_An italic string_ with a *mix* _of_ italic *styles*", output: "An italic string with a mix of italic styles", tokens : [
  191. Token(type: .string, inputString: "An italic string", characterStyles: [CharacterStyle.italic]),
  192. Token(type: .string, inputString: " with a ", characterStyles: []),
  193. Token(type: .string, inputString: "mix", characterStyles: [CharacterStyle.italic]),
  194. Token(type: .string, inputString: " ", characterStyles: []),
  195. Token(type: .string, inputString: "of", characterStyles: [CharacterStyle.italic]),
  196. Token(type: .string, inputString: " italic ", characterStyles: []),
  197. Token(type: .string, inputString: "styles", characterStyles: [CharacterStyle.italic])
  198. ])
  199. results = self.attempt(challenge)
  200. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  201. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  202. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  203. XCTAssertEqual(results.attributedString.string, challenge.output)
  204. challenge = TokenTest(input: "\\_A normal string\\_", output: "_A normal string_", tokens: [
  205. Token(type: .string, inputString: "_A normal string_", characterStyles: [])
  206. ])
  207. results = self.attempt(challenge)
  208. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  209. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  210. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  211. XCTAssertEqual(results.attributedString.string, challenge.output)
  212. challenge = TokenTest(input: "A string with \\_escaped\\_ underscores", output: "A string with _escaped_ underscores", tokens: [
  213. Token(type: .string, inputString: "A string with _escaped_ underscores", characterStyles: [])
  214. ])
  215. results = self.attempt(challenge)
  216. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  217. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  218. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  219. XCTAssertEqual(results.attributedString.string, challenge.output)
  220. challenge = TokenTest(input: """
  221. An asterisk: *
  222. Line break
  223. """, output: """
  224. An asterisk: *
  225. Line break
  226. """, tokens: [
  227. Token(type: .string, inputString: "An asterisk: *", characterStyles: []),
  228. Token(type: .string, inputString: "Line break", characterStyles: [])
  229. ])
  230. results = self.attempt(challenge)
  231. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  232. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  233. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  234. XCTAssertEqual(results.attributedString.string, challenge.output)
  235. }
  236. func testThatStrikethroughTraitsAreRecognised() {
  237. challenge = TokenTest(input: "~~An~~A crossed-out string", output: "AnA crossed-out string", tokens: [
  238. Token(type: .string, inputString: "An", characterStyles: [CharacterStyle.strikethrough]),
  239. Token(type: .string, inputString: "A crossed-out string", characterStyles: [])
  240. ])
  241. results = self.attempt(challenge)
  242. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  243. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  244. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  245. challenge = TokenTest(input: "A **Bold** string and a ~~removed~~crossed-out string", output: "A Bold string and a removedcrossed-out string", tokens: [
  246. Token(type: .string, inputString: "A ", characterStyles: []),
  247. Token(type: .string, inputString: "Bold", characterStyles: [CharacterStyle.bold]),
  248. Token(type: .string, inputString: " string and a ", characterStyles: []),
  249. Token(type: .string, inputString: "removed", characterStyles: [CharacterStyle.strikethrough]),
  250. Token(type: .string, inputString: "crossed-out string", characterStyles: [])
  251. ])
  252. results = self.attempt(challenge)
  253. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  254. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  255. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  256. challenge = TokenTest(input: "\\~\\~removed\\~\\~crossed-out string. ~This should be ignored~", output: "~~removed~~crossed-out string. ~This should be ignored~", tokens: [
  257. Token(type: .string, inputString: "~~removed~~crossed-out string. ~This should be ignored~", characterStyles: [])
  258. ])
  259. results = self.attempt(challenge)
  260. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  261. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  262. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  263. }
  264. func testThatMixedTraitsAreRecognised() {
  265. challenge = TokenTest(input: "__A bold string__ with a **mix** **of** bold __styles__", output: "A bold string with a mix of bold styles", tokens : [
  266. Token(type: .string, inputString: "A bold string", characterStyles: [CharacterStyle.bold]),
  267. Token(type: .string, inputString: "with a ", characterStyles: []),
  268. Token(type: .string, inputString: "mix", characterStyles: [CharacterStyle.bold]),
  269. Token(type: .string, inputString: " ", characterStyles: []),
  270. Token(type: .string, inputString: "of", characterStyles: [CharacterStyle.bold]),
  271. Token(type: .string, inputString: " bold ", characterStyles: []),
  272. Token(type: .string, inputString: "styles", characterStyles: [CharacterStyle.bold])
  273. ])
  274. results = self.attempt(challenge)
  275. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  276. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  277. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  278. XCTAssertEqual(results.attributedString.string, challenge.output)
  279. challenge = TokenTest(input: "_An italic string_, **follwed by a bold one**, `with some code`, \\*\\*and some\\*\\* \\_escaped\\_ \\`characters\\`, `ending` *with* __more__ variety.", output: "An italic string, follwed by a bold one, with some code, **and some** _escaped_ `characters`, ending with more variety.", tokens : [
  280. Token(type: .string, inputString: "An italic string", characterStyles: [CharacterStyle.italic]),
  281. Token(type: .string, inputString: ", ", characterStyles: []),
  282. Token(type: .string, inputString: "followed by a bold one", characterStyles: [CharacterStyle.bold]),
  283. Token(type: .string, inputString: ", ", characterStyles: []),
  284. Token(type: .string, inputString: "with some code", characterStyles: [CharacterStyle.code]),
  285. Token(type: .string, inputString: ", **and some** _escaped_ `characters`, ", characterStyles: []),
  286. Token(type: .string, inputString: "ending", characterStyles: [CharacterStyle.code]),
  287. Token(type: .string, inputString: " ", characterStyles: []),
  288. Token(type: .string, inputString: "with", characterStyles: [CharacterStyle.italic]),
  289. Token(type: .string, inputString: " ", characterStyles: []),
  290. Token(type: .string, inputString: "more", characterStyles: [CharacterStyle.bold]),
  291. Token(type: .string, inputString: " variety.", characterStyles: [])
  292. ])
  293. results = self.attempt(challenge)
  294. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  295. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  296. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  297. XCTAssertEqual(results.attributedString.string, challenge.output)
  298. }
  299. func testThatExtraCharactersAreHandles() {
  300. challenge = TokenTest(input: "***A bold italic string***", output: "A bold italic string", tokens: [
  301. Token(type: .string, inputString: "A bold italic string", characterStyles: [CharacterStyle.bold, CharacterStyle.italic])
  302. ])
  303. results = self.attempt(challenge)
  304. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  305. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  306. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  307. XCTAssertEqual(results.attributedString.string, challenge.output)
  308. challenge = TokenTest(input: "A string with a ****bold italic**** word", output: "A string with a *bold italic* word", tokens: [
  309. Token(type: .string, inputString: "A string with a ", characterStyles: []),
  310. Token(type: .string, inputString: "*bold italic*", characterStyles: [CharacterStyle.bold, CharacterStyle.italic]),
  311. Token(type: .string, inputString: " word", characterStyles: [])
  312. ])
  313. results = self.attempt(challenge)
  314. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  315. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  316. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  317. XCTAssertEqual(results.attributedString.string, challenge.output)
  318. challenge = TokenTest(input: "A string with a ****bold italic*** word", output: "A string with a *bold italic word", tokens: [
  319. Token(type: .string, inputString: "A string with a ", characterStyles: []),
  320. Token(type: .string, inputString: "*bold italic", characterStyles: [CharacterStyle.bold, CharacterStyle.italic]),
  321. Token(type: .string, inputString: " word", characterStyles: [])
  322. ])
  323. results = self.attempt(challenge)
  324. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  325. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  326. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  327. XCTAssertEqual(results.attributedString.string, challenge.output)
  328. challenge = TokenTest(input: "A string with a ***bold** italic* word", output: "A string with a bold italic word", tokens: [
  329. Token(type: .string, inputString: "A string with a ", characterStyles: []),
  330. Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold, CharacterStyle.italic]),
  331. Token(type: .string, inputString: " italic", characterStyles: [CharacterStyle.italic]),
  332. Token(type: .string, inputString: " word", characterStyles: [])
  333. ])
  334. results = self.attempt(challenge)
  335. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  336. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  337. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  338. XCTAssertEqual(results.attributedString.string, challenge.output)
  339. challenge = TokenTest(input: "A string with a **bold*italic*bold** word", output: "A string with a bolditalicbold word", tokens: [
  340. Token(type: .string, inputString: "A string with a ", characterStyles: []),
  341. Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold]),
  342. Token(type: .string, inputString: "italic", characterStyles: [CharacterStyle.bold, CharacterStyle.italic]),
  343. Token(type: .string, inputString: "bold", characterStyles: [CharacterStyle.bold]),
  344. Token(type: .string, inputString: " word", characterStyles: [])
  345. ])
  346. results = self.attempt(challenge)
  347. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  348. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  349. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  350. XCTAssertEqual(results.attributedString.string, challenge.output)
  351. }
  352. // The new version of SwiftyMarkdown is a lot more strict than the old version, although this may change in future
  353. func offtestThatMarkdownMistakesAreHandledAppropriately() {
  354. let mismatchedBoldCharactersAtStart = "**This should be bold*"
  355. let mismatchedBoldCharactersWithin = "A string *that should be italic**"
  356. var md = SwiftyMarkdown(string: mismatchedBoldCharactersAtStart)
  357. XCTAssertEqual(md.attributedString().string, "This should be bold")
  358. md = SwiftyMarkdown(string: mismatchedBoldCharactersWithin)
  359. XCTAssertEqual(md.attributedString().string, "A string that should be italic")
  360. }
  361. func offtestAdvancedEscaping() {
  362. challenge = TokenTest(input: "\\***A normal string*\\**", output: "**A normal string*", tokens: [
  363. Token(type: .string, inputString: "**", characterStyles: []),
  364. Token(type: .string, inputString: "A normal string", characterStyles: [CharacterStyle.italic]),
  365. Token(type: .string, inputString: "**", characterStyles: [])
  366. ])
  367. results = self.attempt(challenge)
  368. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  369. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  370. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  371. XCTAssertEqual(results.attributedString.string, challenge.output)
  372. challenge = TokenTest(input: "A string with randomly *\\**escaped**\\* asterisks", output: "A string with randomly **escaped** asterisks", tokens: [
  373. Token(type: .string, inputString: "A string with randomly **", characterStyles: []),
  374. Token(type: .string, inputString: "escaped", characterStyles: [CharacterStyle.italic]),
  375. Token(type: .string, inputString: "** asterisks", characterStyles: [])
  376. ])
  377. results = self.attempt(challenge)
  378. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  379. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  380. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  381. XCTAssertEqual(results.attributedString.string, challenge.output)
  382. }
  383. func testThatAsterisksAndUnderscoresNotAttachedToWordsAreNotRemoved() {
  384. let asteriskFullStop = "Two asterisks followed by a full stop: **."
  385. let asteriskWithBold = "A **bold** word followed by an asterisk * "
  386. let underscoreFullStop = "Two underscores followed by a full stop: __."
  387. let asteriskComma = "An asterisk followed by a full stop: *, *"
  388. let backtickSpace = "A backtick followed by a space: `"
  389. let underscoreSpace = "An underscore followed by a space: _"
  390. let backtickComma = "A backtick followed by a space: `, `"
  391. let underscoreComma = "An underscore followed by a space: _, _"
  392. let backtickWithCode = "A `code` word followed by a backtick ` "
  393. let underscoreWithItalic = "An _italic_ word followed by an underscore _ "
  394. var md = SwiftyMarkdown(string: backtickSpace)
  395. SwiftyMarkdown.characterRules = self.defaultRules
  396. XCTAssertEqual(md.attributedString().string, backtickSpace)
  397. md = SwiftyMarkdown(string: underscoreSpace)
  398. XCTAssertEqual(md.attributedString().string, underscoreSpace)
  399. md = SwiftyMarkdown(string: asteriskFullStop)
  400. XCTAssertEqual(md.attributedString().string, asteriskFullStop)
  401. md = SwiftyMarkdown(string: underscoreFullStop)
  402. XCTAssertEqual(md.attributedString().string, underscoreFullStop)
  403. md = SwiftyMarkdown(string: asteriskComma)
  404. XCTAssertEqual(md.attributedString().string, asteriskComma)
  405. md = SwiftyMarkdown(string: backtickComma)
  406. XCTAssertEqual(md.attributedString().string, backtickComma)
  407. md = SwiftyMarkdown(string: underscoreComma)
  408. XCTAssertEqual(md.attributedString().string, underscoreComma)
  409. md = SwiftyMarkdown(string: asteriskWithBold)
  410. XCTAssertEqual(md.attributedString().string, "A bold word followed by an asterisk *")
  411. md = SwiftyMarkdown(string: backtickWithCode)
  412. XCTAssertEqual(md.attributedString().string, "A code word followed by a backtick `")
  413. md = SwiftyMarkdown(string: underscoreWithItalic)
  414. XCTAssertEqual(md.attributedString().string, "An italic word followed by an underscore _")
  415. }
  416. func testReportedCrashingStrings() {
  417. challenge = TokenTest(input: "[**\\!bang**](https://duckduckgo.com/bang)", output: "\\!bang", tokens: [
  418. Token(type: .string, inputString: "\\!bang", characterStyles: [CharacterStyle.bold, CharacterStyle.link])
  419. ])
  420. results = self.attempt(challenge)
  421. XCTAssertEqual(challenge.tokens.count, results.stringTokens.count)
  422. XCTAssertEqual(results.tokens.map({ $0.outputString }).joined(), challenge.output)
  423. XCTAssertEqual(results.foundStyles, results.expectedStyles)
  424. XCTAssertEqual(results.attributedString.string, challenge.output)
  425. }
  426. }