@testable import PureYAML import Testing /// A tag shorthand using a named handle (`!handle!suffix`) must be declared by a `%TAG` directive /// in the document that uses it; the handle does not carry across documents. The ported engine is /// strict (official suite case QLJ7): an undeclared handle fails the parse, and the validation /// report carries it as a parse diagnostic. These prove the error is exact: it fires for an /// undeclared handle and stays silent for a declared one, a local tag, the secondary handle, and a /// `!x!` that is only scalar content. @Suite("Undefined tag handle") struct UndefinedTagHandleTests { private func codes(_ yaml: String) -> [String] { PureYAML.validationReport(yaml).diagnostics.compactMap(\.code) } @Test("A handle not redeclared in a later document is flagged there, not in the declaring one") func test_handleScopeIsPerDocument() { let yaml = """ %TAG !prefix! tag:example.com,2011: --- !prefix!A a: b --- !prefix!B c: d """ // The ported engine is strict (official suite case QLJ7): the second document, which // did not redeclare the handle, fails the parse, and the report carries that failure // as a parse diagnostic instead of the old permissive-parse pre-pass diagnostic. let report = PureYAML.validationReport(yaml) let parseErrors = report.diagnostics.filter { $0.kind == .parse && $0.severity == .error } #expect(parseErrors.count == 1) #expect(parseErrors.first?.reason.contains("undefined tag handle") == true) #expect(parseErrors.first?.line == 4) } @Test("A handle redeclared for each document is accepted with no diagnostic") func test_redeclaredHandleIsClean() { let yaml = """ %TAG !m! !my- --- !m!light fluorescent ... %TAG !m! !my- --- !m!light green """ #expect(!codes(yaml).contains("undefinedTagHandle")) } @Test("A local tag, the secondary handle, and a verbatim tag are not handle references") func test_nonHandleTagsAreClean() { #expect(!codes("a: !foo bar").contains("undefinedTagHandle")) #expect(!codes("a: !!str x").contains("undefinedTagHandle")) #expect(!codes("a: ! y").contains("undefinedTagHandle")) } @Test("A bang pair inside scalar content is not a tag and is never flagged") func test_noFalsePositiveInScalarContent() { #expect(!codes("msg: hello !world! bye").contains("undefinedTagHandle")) #expect(!codes("quoted: \"a !x! b\"").contains("undefinedTagHandle")) } }