import Testing @testable import PureXML @Suite("XSLT method=html output") struct XSLTHTMLOutputTests { private let xsl = "xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"" private func transform(_ stylesheet: String, _ source: String) throws -> String { try PureXML.XSLT.transform(stylesheet: stylesheet, source: source) } private func htmlStyle(_ body: String) -> String { """ \(body) """ } @Test("A void element is emitted without a self-closing slash") func test_voidElement() throws { let out = try transform(htmlStyle("
"), "") #expect(out == "
") } @Test("A non-void empty element keeps an explicit end tag") func test_nonVoid() throws { let out = try transform(htmlStyle("
"), "") #expect(out == "
") } @Test("Raw-text element content is not escaped") func test_rawText() throws { let out = try transform(htmlStyle(""), "") #expect(out.contains("if (a < b) x()")) #expect(!out.contains("<")) } @Test("The html method leaves < and > literal in an attribute value") func test_attributeAngleBrackets() throws { // XSLT 1.0 16.2: the html output method does not escape `<` in an // attribute value (nor `>`), unlike the xml method. `&` and `"` still // escape (Apache Xalan output49, output74). let out = try transform(htmlStyle("&"\">t"), "") #expect(out == "&"\">t") } @Test("The xml method still escapes < in an attribute value") func test_xmlAttributeStillEscapes() throws { let style = """ t """ #expect(try transform(style, "") == "t") } @Test("the html method percent-escapes non-ASCII and control chars in URI-valued attributes") func test_uriAttributeEscaping() throws { // XSLT 1.0 16.2 / HTML 4.01 B.2.1: a URI-valued attribute (cite, href, // src, ...) percent-escapes non-ASCII (the UTF-8 bytes) and control/space, // keeping `"` and `&` as entities; a non-URI attribute (title) keeps its // ordinary html escaping. Apache Xalan output32. let out = try transform( htmlStyle(""), "", ) #expect(out == "") } @Test("URI-attribute percent-escaping is idempotent") func test_uriEscapingIdempotent() throws { // A space becomes %20 once; an already-escaped value is stable because a // literal `%` is left as is (so a parse-serialize round-trip converges). #expect(try transform(htmlStyle(""), "") == "") #expect(try transform(htmlStyle(""), "") == "") } @Test("the html method serializes a namespaced element as XML, not HTML") func test_namespacedElementAsXML() throws { // XSLT 1.0 16.2: an element whose expanded-name has a non-null namespace // URI is output as XML (empty elements self-close, the namespace is // declared once), not HTML; a null-namespace element stays HTML (see // test_voidElement). The html serializer otherwise left empty namespaced // elements unclosed and repeated xmlns on every element. let out = try transform(htmlStyle(""), "") #expect(out == "") } @Test("The XML output method still self-closes empty elements") func test_xmlStillSelfCloses() throws { let style = """
""" #expect(try transform(style, "") == "
") } }