mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-26 10:11:00 +00:00
Bugfix 1459 - Escape ~ character as markdown (#1561)
* Add simple test for escaping markdown content in statuses * Add ~ as markdown character to be escaped in statuses The ~ isn't documented in the original markdown syntax docs but is commonly used (including by AttributedString) to surround text formatted with a strikethrough.
This commit is contained in:
parent
30f9da06c8
commit
077b0d269d
2 changed files with 33 additions and 9 deletions
|
@ -37,10 +37,12 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
|
||||||
|
|
||||||
if !alreadyDecoded {
|
if !alreadyDecoded {
|
||||||
// https://daringfireball.net/projects/markdown/syntax
|
// https://daringfireball.net/projects/markdown/syntax
|
||||||
// Pre-escape \ ` _ * and [ as these are the only
|
// Pre-escape \ ` _ * ~ and [ as these are the only
|
||||||
// characters the markdown parser used picks up
|
// characters the markdown parser uses when it renders
|
||||||
// when it renders to attributed text
|
// to attributed text. Note that ~ for strikethrough is
|
||||||
main_regex = try? NSRegularExpression(pattern: "([\\*\\`\\[\\\\])", options: .caseInsensitive)
|
// not documented in the syntax docs but is used by
|
||||||
|
// AttributedString.
|
||||||
|
main_regex = try? NSRegularExpression(pattern: "([\\*\\`\\~\\[\\\\])", options: .caseInsensitive)
|
||||||
// don't escape underscores that are between colons, they are most likely custom emoji
|
// don't escape underscores that are between colons, they are most likely custom emoji
|
||||||
underscore_regex = try? NSRegularExpression(pattern: "(?!\\B:[^:]*)(_)(?![^:]*:\\B)", options: .caseInsensitive)
|
underscore_regex = try? NSRegularExpression(pattern: "(?!\\B:[^:]*)(_)(?![^:]*:\\B)", options: .caseInsensitive)
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ final class HTMLStringTests: XCTestCase {
|
||||||
|
|
||||||
let extendedCharQuery = URL(string: "http://test.com/blah/city?name=京都市", encodePath: true)
|
let extendedCharQuery = URL(string: "http://test.com/blah/city?name=京都市", encodePath: true)
|
||||||
XCTAssertEqual("http://test.com/blah/city?name=%E4%BA%AC%E9%83%BD%E5%B8%82", extendedCharQuery?.absoluteString)
|
XCTAssertEqual("http://test.com/blah/city?name=%E4%BA%AC%E9%83%BD%E5%B8%82", extendedCharQuery?.absoluteString)
|
||||||
|
|
||||||
// Double encoding will happen if you ask to encodePath on an already encoded string
|
// Double encoding will happen if you ask to encodePath on an already encoded string
|
||||||
let alreadyEncodedPath = URL(string: "https://en.wikipedia.org/wiki/Elbbr%C3%BCcken_station", encodePath: true)
|
let alreadyEncodedPath = URL(string: "https://en.wikipedia.org/wiki/Elbbr%C3%BCcken_station", encodePath: true)
|
||||||
XCTAssertEqual("https://en.wikipedia.org/wiki/Elbbr%25C3%25BCcken_station", alreadyEncodedPath?.absoluteString)
|
XCTAssertEqual("https://en.wikipedia.org/wiki/Elbbr%25C3%25BCcken_station", alreadyEncodedPath?.absoluteString)
|
||||||
|
@ -27,7 +27,7 @@ final class HTMLStringTests: XCTestCase {
|
||||||
|
|
||||||
func testHTMLStringInit() throws {
|
func testHTMLStringInit() throws {
|
||||||
let decoder = JSONDecoder()
|
let decoder = JSONDecoder()
|
||||||
|
|
||||||
let basicContent = "\"<p>This is a test</p>\""
|
let basicContent = "\"<p>This is a test</p>\""
|
||||||
var htmlString = try decoder.decode(HTMLString.self, from: Data(basicContent.utf8))
|
var htmlString = try decoder.decode(HTMLString.self, from: Data(basicContent.utf8))
|
||||||
XCTAssertEqual("This is a test", htmlString.asRawText)
|
XCTAssertEqual("This is a test", htmlString.asRawText)
|
||||||
|
@ -35,7 +35,7 @@ final class HTMLStringTests: XCTestCase {
|
||||||
XCTAssertEqual("This is a test", htmlString.asMarkdown)
|
XCTAssertEqual("This is a test", htmlString.asMarkdown)
|
||||||
XCTAssertEqual(0, htmlString.statusesURLs.count)
|
XCTAssertEqual(0, htmlString.statusesURLs.count)
|
||||||
XCTAssertEqual(0, htmlString.links.count)
|
XCTAssertEqual(0, htmlString.links.count)
|
||||||
|
|
||||||
let basicLink = "\"<p>This is a <a href=\\\"https://test.com\\\">test</a></p>\""
|
let basicLink = "\"<p>This is a <a href=\\\"https://test.com\\\">test</a></p>\""
|
||||||
htmlString = try decoder.decode(HTMLString.self, from: Data(basicLink.utf8))
|
htmlString = try decoder.decode(HTMLString.self, from: Data(basicLink.utf8))
|
||||||
XCTAssertEqual("This is a test", htmlString.asRawText)
|
XCTAssertEqual("This is a test", htmlString.asRawText)
|
||||||
|
@ -45,7 +45,7 @@ final class HTMLStringTests: XCTestCase {
|
||||||
XCTAssertEqual(1, htmlString.links.count)
|
XCTAssertEqual(1, htmlString.links.count)
|
||||||
XCTAssertEqual("https://test.com", htmlString.links[0].url.absoluteString)
|
XCTAssertEqual("https://test.com", htmlString.links[0].url.absoluteString)
|
||||||
XCTAssertEqual("test", htmlString.links[0].displayString)
|
XCTAssertEqual("test", htmlString.links[0].displayString)
|
||||||
|
|
||||||
let extendedCharLink = "\"<p>This is a <a href=\\\"https://test.com/goßëña\\\">test</a></p>\""
|
let extendedCharLink = "\"<p>This is a <a href=\\\"https://test.com/goßëña\\\">test</a></p>\""
|
||||||
htmlString = try decoder.decode(HTMLString.self, from: Data(extendedCharLink.utf8))
|
htmlString = try decoder.decode(HTMLString.self, from: Data(extendedCharLink.utf8))
|
||||||
XCTAssertEqual("This is a test", htmlString.asRawText)
|
XCTAssertEqual("This is a test", htmlString.asRawText)
|
||||||
|
@ -55,7 +55,7 @@ final class HTMLStringTests: XCTestCase {
|
||||||
XCTAssertEqual(1, htmlString.links.count)
|
XCTAssertEqual(1, htmlString.links.count)
|
||||||
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
|
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
|
||||||
XCTAssertEqual("test", htmlString.links[0].displayString)
|
XCTAssertEqual("test", htmlString.links[0].displayString)
|
||||||
|
|
||||||
let alreadyEncodedLink = "\"<p>This is a <a href=\\\"https://test.com/go%C3%9F%C3%AB%C3%B1a\\\">test</a></p>\""
|
let alreadyEncodedLink = "\"<p>This is a <a href=\\\"https://test.com/go%C3%9F%C3%AB%C3%B1a\\\">test</a></p>\""
|
||||||
htmlString = try decoder.decode(HTMLString.self, from: Data(alreadyEncodedLink.utf8))
|
htmlString = try decoder.decode(HTMLString.self, from: Data(alreadyEncodedLink.utf8))
|
||||||
XCTAssertEqual("This is a test", htmlString.asRawText)
|
XCTAssertEqual("This is a test", htmlString.asRawText)
|
||||||
|
@ -66,4 +66,26 @@ final class HTMLStringTests: XCTestCase {
|
||||||
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
|
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
|
||||||
XCTAssertEqual("test", htmlString.links[0].displayString)
|
XCTAssertEqual("test", htmlString.links[0].displayString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testHTMLStringInit_markdownEscaping() throws {
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
|
||||||
|
let stdMarkdownContent = "\"<p>This [*is*] `a`\\n**test**</p>\""
|
||||||
|
var htmlString = try decoder.decode(HTMLString.self, from: Data(stdMarkdownContent.utf8))
|
||||||
|
XCTAssertEqual("This [*is*] `a`\n**test**", htmlString.asRawText)
|
||||||
|
XCTAssertEqual("<p>This [*is*] `a`\n**test**</p>", htmlString.htmlValue)
|
||||||
|
XCTAssertEqual("This \\[\\*is\\*] \\`a\\` \\*\\*test\\*\\*", htmlString.asMarkdown)
|
||||||
|
|
||||||
|
let underscoreContent = "\"<p>This _is_ an :emoji_maybe:</p>\""
|
||||||
|
htmlString = try decoder.decode(HTMLString.self, from: Data(underscoreContent.utf8))
|
||||||
|
XCTAssertEqual("This _is_ an :emoji_maybe:", htmlString.asRawText)
|
||||||
|
XCTAssertEqual("<p>This _is_ an :emoji_maybe:</p>", htmlString.htmlValue)
|
||||||
|
XCTAssertEqual("This \\_is\\_ an :emoji_maybe:", htmlString.asMarkdown)
|
||||||
|
|
||||||
|
let strikeContent = "\"<p>This ~is~ a\\n`test`</p>\""
|
||||||
|
htmlString = try decoder.decode(HTMLString.self, from: Data(strikeContent.utf8))
|
||||||
|
XCTAssertEqual("This ~is~ a\n`test`", htmlString.asRawText)
|
||||||
|
XCTAssertEqual("<p>This ~is~ a\n`test`</p>", htmlString.htmlValue)
|
||||||
|
XCTAssertEqual("This \\~is\\~ a \\`test\\`", htmlString.asMarkdown)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue