PureYAML/Tests/CommentWhitespaceTests.swift
Mihaela M 1d07fce635 fix(parsing): reject a comment glued to earlier content on its line
A '#' that begins a comment must be preceded by whitespace or open the
line; glued to earlier same-line content (e.g. "value"# c, [ a, b ]#c,
>#c, a flow entry then ,#c) it is neither a comment nor, in those
positions, plain-scalar content, so the document is malformed. Such input
was previously accepted as a comment.

A '#' that opens a line, follows a space, or sits inside a plain scalar
(a#b, where it stays literal content and never reaches this check) is
unaffected. The scanner tracks whether a real token has been scanned on
the current physical line, reset on each line break, rather than comparing
token line numbers: the streaming tokenizer drains its token buffer
between scans, and a block scalar's blank line emits an empty scalar
attributed to the next line, either of which would misread as content.

Measured against the official YAML test-suite, parse-level conformance
rises from 243/333 (73.0%) to 247/333 (74.2%): four wrongly-accepted
invalid documents are now rejected, with no valid document regressing.
The scalar-scanning routines move to Scanner.Scalars.swift to keep the
file within the length limit.
2026-06-27 15:53:16 +02:00

36 lines
1.4 KiB
Swift

@testable import PureYAML
import Testing
@Suite("Comments must be preceded by whitespace")
struct CommentWhitespaceTests {
@Test("A comment glued to earlier content on its line is rejected", arguments: [
"key: \"value\"# comment\n", // after a quoted scalar
"[ a, b ]#comment\n", // after a flow sequence close
"{ a: b }#comment\n", // after a flow mapping close
"block: >#comment\n x\n", // after a block scalar header
"[ a,#comment\n]\n", // after a flow entry separator
])
func test_gluedCommentIsRejected(_ yaml: String) throws {
#expect(throws: PureYAML.Parsing.ParseError.self) {
try PureYAML.parse(yaml)
}
}
@Test("A comment preceded by whitespace or opening a line is accepted", arguments: [
"key: \"value\" # comment\n", // a space before the comment
"# comment\nkey: v\n", // a comment opening the document
"a: 1\n # comment\nb: 2\n", // an indented comment line
"[ a,\n # comment\n b ]\n", // a comment line inside a flow collection
])
func test_wellSpacedCommentIsAccepted(_ yaml: String) throws {
_ = try PureYAML.parse(yaml)
}
@Test("A '#' inside a plain scalar stays literal content, not a comment")
func test_hashInsidePlainScalar() throws {
#expect(try PureYAML.parse("key: a#b\n") == .mapping(.init([
.init(key: "key", value: .string("a#b")),
])))
}
}