import Testing @testable import PureXML /// The output-method behaviors of XSLT 1.0 section 16 added in the xalan /// burn-down (#130): disable-output-escaping (including its 16.4 fragment /// rule and the marker-safety gate), CDATA "]]>" splitting, the simplified /// stylesheet syntax, the html default method with META injection, key() /// inside document() trees, and the attribute-start following/preceding axes. @Suite("XSLT output methods and runtime corners") struct XSLTOutputMethodTests { private let xsl = "xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"" @Test("disable-output-escaping writes text through unescaped") func test_disableOutputEscaping() throws { let style = """ <P>&nbsp;</P> """ #expect(try PureXML.XSLT.transform(stylesheet: style, source: "") == "

 

") } @Test("disable-output-escaping does not survive a fragment round-trip (16.4)") func test_rawTextFragmentRoundTrip() throws { let style = """ a <b> c """ #expect(try PureXML.XSLT.transform(stylesheet: style, source: "") == "a <b> c") } @Test("disable-output-escaping is ignored for an attribute value (16.4)") func test_disableOutputEscapingIgnoredOffTextNode() throws { // 16.4: disabling escaping for a value used as an attribute (not a text // node) is an error; the recovery ignores it, so the attribute escapes // `<`/`>` while a sibling text node keeps it raw (Apache Xalan output75). let body = "" + "<x>" + "<t>" let style = """ \(body) """ #expect(try PureXML.XSLT.transform(stylesheet: style, source: "") == "") } @Test("Source text holding the private-use marker characters is untouched") func test_markerCharactersInSource() throws { let style = """ """ let source = "a\u{E000}<kept>\u{E001}b" #expect(try PureXML.XSLT.transform(stylesheet: style, source: source) == "a\u{E000}<kept>\u{E001}b") } @Test("cdata-section-elements split ]]> across section boundaries") func test_cdataTerminatorSplitting() throws { let style = """ ]]> """ #expect(try PureXML.XSLT.transform(stylesheet: style, source: "") == "]]>") } @Test("A literal result element with xsl:version is a one-template stylesheet (2.3)") func test_simplifiedSyntax() throws { let style = """ value: """ let result = try PureXML.XSLT.transform(stylesheet: style, source: "7") #expect(result.hasSuffix("value: 7")) } @Test("A null-namespace html root selects the html method and gains META (16.1/16.2)") func test_htmlDefaultMethod() throws { let style = """ t
""" let result = try PureXML.XSLT.transform(stylesheet: style, source: "") #expect(result == "t
") } @Test("key() indexes the current node's own document, document() trees included") func test_keyPerDocument() throws { let style = """ """ let result = try PureXML.XSLT.transform( stylesheet: style, source: "local", documentLoader: { $0 == "other.xml" ? "external" : nil }, ) #expect(result == "external") } @Test("following and preceding work from attribute starts") func test_axesFromAttributes() throws { let style = """

""" let source = "" // Document order places the attribute after b and before b's children, // so following includes inner and c; preceding holds a only (r is an // ancestor). #expect(try PureXML.XSLT.transform(stylesheet: style, source: source) == "inner c

a

") } @Test("html boolean attributes minimize when the value repeats the name") func test_htmlBooleanAttributes() throws { let style = """
""" #expect(try PureXML.XSLT.transform(stylesheet: style, source: "") == "
") } @Test("Stylesheet and source entities resolve through the document loader") func test_loaderEntityResolution() throws { let style = """ """ let result = try PureXML.XSLT.transform( stylesheet: style, source: "", documentLoader: { $0 == "ents.dtd" ? "" : nil }, ) #expect(result == "a\u{E6}b") } @Test("A comment ending in a hyphen is well-formed in html output too") func test_htmlCommentHyphenSafety() throws { // The html output method must also apply the section-16 comment recovery, // so a trailing hyphen does not produce a malformed ``. let style = """ x- """ #expect(try PureXML.XSLT.transform(stylesheet: style, source: "") == "") } }