Adds a datatypeLibrary-aware datatype resolver to the XML-syntax parser: the in-scope library is inherited from the nearest ancestor, the default (empty) library defines only string and token, and the W3C XML Schema library defines the full built-in set. A type the in-scope library does not define is an unknown datatype, so the <data>/<value> pattern matches nothing rather than silently validating. Adds an nsNameExcept name-class case so nsName with an <except> child (XML syntax) and prefix:* - name subtraction (compact syntax) narrow a namespace wildcard. The compact lexer splits prefix:* into a trailing- colon word plus a star symbol, which the parser now recognizes. Existing RELAX NG facet tests declared XSD types without the library and relied on lenient resolution; they now declare the XSD datatypeLibrary, matching what a conformant processor requires.
52 lines
1.7 KiB
Swift
52 lines
1.7 KiB
Swift
@testable import PureXML
|
|
import Testing
|
|
|
|
@Suite("RELAX NG data param facets")
|
|
struct RelaxNGDataParamTests {
|
|
private let rngNamespace = "xmlns=\"http://relaxng.org/ns/structure/1.0\" datatypeLibrary=\"http://www.w3.org/2001/XMLSchema-datatypes\""
|
|
|
|
private func valid(_ rng: String, _ xml: String) throws -> Bool {
|
|
try PureXML.Schema.RelaxNG(rng).validate(xml)
|
|
}
|
|
|
|
@Test("A minLength param constrains a data value")
|
|
func test_minLength() throws {
|
|
let rng = """
|
|
<element name="code" \(rngNamespace)>
|
|
<data type="string"><param name="minLength">3</param></data>
|
|
</element>
|
|
"""
|
|
#expect(try valid(rng, "<code>abc</code>"))
|
|
#expect(try !valid(rng, "<code>ab</code>"))
|
|
}
|
|
|
|
@Test("A maxInclusive param constrains a numeric data value")
|
|
func test_maxInclusive() throws {
|
|
let rng = """
|
|
<element name="n" \(rngNamespace)>
|
|
<data type="integer"><param name="maxInclusive">10</param></data>
|
|
</element>
|
|
"""
|
|
#expect(try valid(rng, "<n>5</n>"))
|
|
#expect(try !valid(rng, "<n>20</n>"))
|
|
}
|
|
|
|
@Test("A pattern param constrains a data value")
|
|
func test_pattern() throws {
|
|
let rng = """
|
|
<element name="sku" \(rngNamespace)>
|
|
<data type="string"><param name="pattern">[A-Z]{3}</param></data>
|
|
</element>
|
|
"""
|
|
#expect(try valid(rng, "<sku>ABC</sku>"))
|
|
#expect(try !valid(rng, "<sku>abc</sku>"))
|
|
}
|
|
|
|
@Test("Data with no params still validates against its base type")
|
|
func test_noParams() throws {
|
|
let rng = "<element name=\"n\" \(rngNamespace)><data type=\"integer\"/></element>"
|
|
#expect(try valid(rng, "<n>42</n>"))
|
|
#expect(try !valid(rng, "<n>x</n>"))
|
|
}
|
|
}
|