PureXML/Tests/SchematronTests.swift
Mihaela Mihaljevic 83e6e27d12 style(format): adopt --importgrouping testable-bottom from canonical rules-swift
Group @testable imports at the bottom, per public/rules-swift's swiftformat. A
behavior-preserving import-ordering reformat across 252 files (mostly tests).
--trailingclosures was deliberately not adopted (cosmetic, and swiftformat flags
it as caution-worthy).
2026-06-18 20:33:07 +02:00

78 lines
2.9 KiB
Swift

import Testing
@testable import PureXML
@Suite("Schematron")
struct SchematronTests {
private let schema = """
<schema xmlns="http://purl.oclc.org/dsdl/schematron">
<pattern>
<rule context="book">
<assert test="title">a book must have a title</assert>
<assert test="@isbn">a book must have an isbn</assert>
<report test="count(author) &gt; 2">more than two authors</report>
</rule>
</pattern>
</schema>
"""
private func validate(_ xml: String) throws -> [PureXML.Validation.ValidationError] {
try PureXML.Validation.Schematron(schema: schema).validate(xml)
}
@Test("A conforming document produces no issues")
func test_valid() throws {
let xml = "<library><book isbn=\"1\"><title>T</title><author>A</author></book></library>"
#expect(try validate(xml).isEmpty)
}
@Test("A failed assert is reported as an error located at its context node")
func test_failedAssert() throws {
let xml = "<library><book isbn=\"1\"><author>A</author></book></library>"
let issues = try validate(xml)
#expect(issues.count == 1)
#expect(issues.first?.severity == .error)
#expect(issues.first?.reason == "a book must have a title")
#expect(String(describing: issues[0]) == "a book must have a title at path: library/book")
}
@Test("Multiple failed asserts each report")
func test_multipleAsserts() throws {
let xml = "<library><book><author>A</author></book></library>"
let messages = try validate(xml).map(\.reason)
#expect(messages.contains("a book must have a title"))
#expect(messages.contains("a book must have an isbn"))
}
@Test("A matched report is a warning")
func test_report() throws {
let xml = "<library><book isbn=\"1\"><title>T</title>"
+ "<author>A</author><author>B</author><author>C</author></book></library>"
let issues = try validate(xml)
#expect(issues.count == 1)
#expect(issues.first?.severity == .warning)
#expect(issues.first?.reason == "more than two authors")
}
@Test("Rules fire once per matching node across the document")
func test_perNode() throws {
let xml = "<library>"
+ "<book isbn=\"1\"><title>T</title></book>"
+ "<book><author>A</author></book>"
+ "</library>"
// The second book is missing both title and isbn.
let issues = try validate(xml)
#expect(issues.count == 2)
#expect(issues.allSatisfy { $0.severity == .error })
}
@Test("An invalid test expression is rejected at compile time")
func test_invalidSchema() {
let bad = """
<schema><pattern><rule context="book"><assert test="(">x</assert></rule></pattern></schema>
"""
#expect(throws: Error.self) {
_ = try PureXML.Validation.Schematron(schema: bad)
}
}
}