IceCubes/Packages/Models/Tests/ModelsTests/HTMLStringTests.swift
Grant McSheffrey 30f9da06c8
Support status links with non-ASCII characters (Bugfix 1546) (#1550)
* Allow creation of URL objects from strings containing non-ASCII characters

Adds a new initializer for creating URL objects with a flag to specify that
non-ASCII characters found in the path or query string should first be
URL encoded.

* Add basic test for creating HTMLString objects

* Encode link paths and queries when parsing statuses

It's common to use non-ASCII characters in URLs even though they're technically
invalid characters. Every modern browser handles this by silently encoding
the invalid characters on the user's behalf. However, trying to create a URL
object with un-encoded characters will result in nil so we need to encode the
invalid characters before creating the URL object. The unencoded version
should still be shown in the displayed status.

The parsing of the URL string is a little messy because we can't use the URL
class for this scenario and need to duplicate some of its work.

* Only encode link URLs as a backup

If a URL can be created from a status href, don't try URL encoding
it as this could result in double encoding. Only encode the string
if the creation of a URL fails. This is also more efficient.
2023-08-23 07:08:12 +02:00

70 lines
4.0 KiB
Swift

@testable import Models
import XCTest
final class HTMLStringTests: XCTestCase {
func testURLInit() throws {
XCTAssertNil(URL(string: "go to www.google.com", encodePath: true))
XCTAssertNil(URL(string: "go to www.google.com", encodePath: false))
XCTAssertNil(URL(string: "", encodePath: true))
let simpleUrl = URL(string: "https://www.google.com", encodePath: true)
XCTAssertEqual("https://www.google.com", simpleUrl?.absoluteString)
let urlWithTrailingSlash = URL(string: "https://www.google.com/", encodePath: true)
XCTAssertEqual("https://www.google.com/", urlWithTrailingSlash?.absoluteString)
let extendedCharPath = URL(string: "https://en.wikipedia.org/wiki/Elbbrücken_station", encodePath: true)
XCTAssertEqual("https://en.wikipedia.org/wiki/Elbbr%C3%BCcken_station", extendedCharPath?.absoluteString)
XCTAssertNil(URL(string: "https://en.wikipedia.org/wiki/Elbbrücken_station", encodePath: false))
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)
// 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)
XCTAssertEqual("https://en.wikipedia.org/wiki/Elbbr%25C3%25BCcken_station", alreadyEncodedPath?.absoluteString)
}
func testHTMLStringInit() throws {
let decoder = JSONDecoder()
let basicContent = "\"<p>This is a test</p>\""
var htmlString = try decoder.decode(HTMLString.self, from: Data(basicContent.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
XCTAssertEqual("<p>This is a test</p>", htmlString.htmlValue)
XCTAssertEqual("This is a test", htmlString.asMarkdown)
XCTAssertEqual(0, htmlString.statusesURLs.count)
XCTAssertEqual(0, htmlString.links.count)
let basicLink = "\"<p>This is a <a href=\\\"https://test.com\\\">test</a></p>\""
htmlString = try decoder.decode(HTMLString.self, from: Data(basicLink.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
XCTAssertEqual("<p>This is a <a href=\"https://test.com\">test</a></p>", htmlString.htmlValue)
XCTAssertEqual("This is a [test](https://test.com)", htmlString.asMarkdown)
XCTAssertEqual(0, htmlString.statusesURLs.count)
XCTAssertEqual(1, htmlString.links.count)
XCTAssertEqual("https://test.com", htmlString.links[0].url.absoluteString)
XCTAssertEqual("test", htmlString.links[0].displayString)
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))
XCTAssertEqual("This is a test", htmlString.asRawText)
XCTAssertEqual("<p>This is a <a href=\"https://test.com/goßëña\">test</a></p>", htmlString.htmlValue)
XCTAssertEqual("This is a [test](https://test.com/go%C3%9F%C3%AB%C3%B1a)", htmlString.asMarkdown)
XCTAssertEqual(0, htmlString.statusesURLs.count)
XCTAssertEqual(1, htmlString.links.count)
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
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>\""
htmlString = try decoder.decode(HTMLString.self, from: Data(alreadyEncodedLink.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
XCTAssertEqual("<p>This is a <a href=\"https://test.com/go%C3%9F%C3%AB%C3%B1a\">test</a></p>", htmlString.htmlValue)
XCTAssertEqual("This is a [test](https://test.com/go%C3%9F%C3%AB%C3%B1a)", htmlString.asMarkdown)
XCTAssertEqual(0, htmlString.statusesURLs.count)
XCTAssertEqual(1, htmlString.links.count)
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
XCTAssertEqual("test", htmlString.links[0].displayString)
}
}