The validation module already implemented the composable-rule idiom under its own names (Check/Issue/SubjectContext) and a value-type Validator with duplicated traversal machinery per layer. Renamed the core types to the canonical names (Validation/ValidationError/ValidationErrorCollection/ ValidationContext/BuiltinValidation/AnyValidation), converted Validator to a reference-type class with the two-tier default-rule split, and genericized it over both Subject and Document via a new Traversable protocol so the model and tagged layers share one walk engine instead of two copies. Wired the JSON-representability rule set into the same shape and closed the two missing pieces (unwrap combinator, JSON coverage/config-pin tests).
146 lines
4.2 KiB
Swift
146 lines
4.2 KiB
Swift
@testable import PureYAML
|
|
import Testing
|
|
|
|
@Suite("Event Streaming Parser")
|
|
struct EventStreamingParserTests {
|
|
@Test(
|
|
"Streaming composer matches full event composer for single documents",
|
|
arguments: EventStreamingFixtures.singleDocuments,
|
|
)
|
|
func test_streamingComposerMatchesFullEventComposer(testCase: EventStreamingFixtures.DocumentCase) throws {
|
|
let parser = PureYAML.Parsing.Parser()
|
|
let streaming = try parser.parse(testCase.yaml)
|
|
let fullEvents = try composeSingleDocumentWithFullEvents(testCase.yaml)
|
|
|
|
#expect(streaming == fullEvents)
|
|
}
|
|
|
|
@Test(
|
|
"Streaming composer matches full event composer for streams",
|
|
arguments: EventStreamingFixtures.streams,
|
|
)
|
|
func test_streamingComposerMatchesFullEventComposerForStreams(testCase: EventStreamingFixtures.DocumentCase) throws {
|
|
let parser = PureYAML.Parsing.Parser()
|
|
let streaming = try parser.parseStream(testCase.yaml)
|
|
let fullEvents = try composeStreamWithFullEvents(testCase.yaml)
|
|
|
|
#expect(streaming == fullEvents)
|
|
}
|
|
|
|
@Test("Streaming parser preserves duplicate keys for validation")
|
|
func test_streamingParserPreservesDuplicateKeysForValidation() throws {
|
|
let value = try PureYAML.parse("""
|
|
root:
|
|
title: First
|
|
title: Second
|
|
flow: {id: one, id: two}
|
|
""")
|
|
|
|
let issues = PureYAML.Validation.Validator<PureYAML.Model.Value, PureYAML.Model.Value>().collect(value).values
|
|
|
|
#expect(issues.map(\.description) == [
|
|
"Duplicate mapping key 'title' at path: $.root.title",
|
|
"Duplicate mapping key 'id' at path: $.flow.id",
|
|
])
|
|
}
|
|
}
|
|
|
|
enum EventStreamingFixtures {
|
|
struct DocumentCase: CustomTestStringConvertible {
|
|
var name: String
|
|
var yaml: String
|
|
|
|
var testDescription: String {
|
|
name
|
|
}
|
|
}
|
|
|
|
static let singleDocuments = [
|
|
DocumentCase(
|
|
name: "block mappings and sequences",
|
|
yaml: """
|
|
servers:
|
|
- url: /
|
|
description: Default
|
|
""",
|
|
),
|
|
DocumentCase(
|
|
name: "anchors aliases and merge keys",
|
|
yaml: """
|
|
defaults: &defaults
|
|
enabled: true
|
|
retries: 3
|
|
service:
|
|
<<: *defaults
|
|
name: API
|
|
""",
|
|
),
|
|
DocumentCase(
|
|
name: "flow collections and tags",
|
|
yaml: """
|
|
flow: [!Thing &item "value", *item, {tagged: !<tag:example.com,2026:thing> 'it''s'}]
|
|
""",
|
|
),
|
|
DocumentCase(
|
|
name: "block scalars",
|
|
yaml: """
|
|
text: |
|
|
one
|
|
two
|
|
folded: >
|
|
three
|
|
four
|
|
""",
|
|
),
|
|
DocumentCase(
|
|
name: "JSON style input",
|
|
yaml: #"{"openapi":"3.0.0","info":{"title":"JSON API"},"items":["a:b","c"],"enabled":true}"#,
|
|
),
|
|
DocumentCase(
|
|
name: "complex mapping key",
|
|
yaml: """
|
|
? {name: service, version: 1}
|
|
: active
|
|
""",
|
|
),
|
|
]
|
|
|
|
static let streams = [
|
|
DocumentCase(
|
|
name: "multi document sequence stream",
|
|
yaml: """
|
|
---
|
|
- one
|
|
- two
|
|
---
|
|
name: three
|
|
...
|
|
---
|
|
null
|
|
""",
|
|
),
|
|
DocumentCase(
|
|
name: "empty explicit documents",
|
|
yaml: """
|
|
---
|
|
...
|
|
---
|
|
""",
|
|
),
|
|
]
|
|
}
|
|
|
|
private func composeSingleDocumentWithFullEvents(_ yaml: String) throws -> PureYAML.Model.Value {
|
|
let parser = PureYAML.Parsing.Parser()
|
|
let events = try parser.parseEvents(yaml)
|
|
var composer = PureYAML.Parsing.EventComposer(events: events, scalarParser: parser)
|
|
return try composer.compose()
|
|
}
|
|
|
|
private func composeStreamWithFullEvents(_ yaml: String) throws -> [PureYAML.Stream.Document] {
|
|
let parser = PureYAML.Parsing.Parser()
|
|
let events = try parser.parseEvents(yaml)
|
|
var composer = PureYAML.Parsing.EventComposer(events: events, scalarParser: parser)
|
|
return try composer.composeStream()
|
|
}
|