PureYAML/Tests/PureYAMLJSONTests/JSONConvertTests.swift
Mihaela Mihaljevic bf069fad39 feat(json): add PureYAMLJSON product, a standalone YAML <-> JSON converter
PureYAMLJSON is a separate library product layered on the core engine. JSON is
a subset of YAML 1.2, so the existing parser already reads both into one value
tree; this product adds the missing half and the value-level policy:

- JSON.Writer: a pure-Swift RFC-8259 serializer (no Foundation; WASI-clean),
  pretty or compact, rejecting non-string keys and non-finite numbers.
- JSON representability rules expressed in PureYAML's own Validation framework:
  mappingKeysAreStrings and numbersAreFinite join the core mappingKeysAreUnique.
- JSON.Validator: the representability rule set plus issues(for:)/isRepresentable.
- JSON.Convert: standalone convert(_:to:) with the round-trip law (parse ->
  validate representability -> emit -> re-parse must equal the source). To JSON
  rejects complex keys and non-finite numbers; to YAML rejects duplicate keys,
  which are legal in JSON but not in YAML.

19 tests cover the writer, the rules, and both conversion directions including
the dual-rejection edges. Carved out of the catch-all Sources/Tests paths via
exclude so the core PureYAML target is unchanged.
2026-06-25 00:33:40 +02:00

74 lines
3.2 KiB
Swift

import PureYAML
@testable import PureYAMLJSON
import Testing
@Suite("JSON Convert both directions")
struct JSONConvertTests {
private let sampleJSON = """
{"name": "PureYAML", "n": 1, "ratio": 1.5, "open": true, "tags": ["yaml", "json"], "nested": {"a": 1, "b": [null, false]}}
"""
@Test("JSON to YAML is block style and round-trips to the same value")
func test_jsonToYAML() throws {
let yaml = try PureYAML.JSON.Convert.convert(sampleJSON, to: .yaml)
#expect(!yaml.hasPrefix("{"))
#expect(yaml.contains("name: PureYAML"))
#expect(yaml.contains("tags:"))
#expect(try PureYAML.parse(yaml) == PureYAML.parse(sampleJSON))
}
@Test("YAML to JSON round-trips to the same value")
func test_yamlToJSON() throws {
let yaml = "name: PureYAML\nn: 1\nlist:\n - a\n - 2\nnested:\n flag: true"
let json = try PureYAML.JSON.Convert.convert(yaml, to: .json, pretty: false)
#expect(json.hasPrefix("{"))
#expect(try PureYAML.parse(json) == PureYAML.parse(yaml))
}
@Test("JSON to YAML to JSON returns the original document")
func test_jsonRoundTripThroughYAML() throws {
let yaml = try PureYAML.JSON.Convert.convert(sampleJSON, to: .yaml)
let json = try PureYAML.JSON.Convert.convert(yaml, to: .json, pretty: false)
#expect(json == "{\"name\":\"PureYAML\",\"n\":1,\"ratio\":1.5,\"open\":true,\"tags\":[\"yaml\",\"json\"],\"nested\":{\"a\":1,\"b\":[null,false]}}")
}
@Test("YAML to JSON to YAML returns an equivalent document")
func test_yamlRoundTripThroughJSON() throws {
let yaml = "count: 3\nratio: 0.25\nitems:\n - x\n - y\nflag: false"
let value = try PureYAML.parse(yaml)
let json = try PureYAML.JSON.Convert.convert(yaml, to: .json)
let backToYAML = try PureYAML.JSON.Convert.convert(json, to: .yaml)
#expect(try PureYAML.parse(backToYAML) == value)
}
@Test("A string that looks like a bool stays a string both ways")
func test_stringLikeBoolPreserved() throws {
let json = "{\"a\": true, \"b\": \"true\"}"
let yaml = try PureYAML.JSON.Convert.convert(json, to: .yaml)
#expect(try PureYAML.parse(yaml) == PureYAML.parse(json))
let backToJSON = try PureYAML.JSON.Convert.convert(yaml, to: .json, pretty: false)
#expect(backToJSON == "{\"a\":true,\"b\":\"true\"}")
}
@Test("Duplicate keys are rejected both ways (legal JSON, illegal YAML)")
func test_duplicateKeysRejected() {
let duplicated = "{\"a\": 1, \"a\": 2}"
#expect(throws: PureYAML.JSON.Convert.Failure.self) {
_ = try PureYAML.JSON.Convert.convert(duplicated, to: .yaml)
}
#expect(throws: PureYAML.JSON.Convert.Failure.self) {
_ = try PureYAML.JSON.Convert.convert(duplicated, to: .json)
}
}
@Test("A complex YAML key blocks JSON but converts to YAML")
func test_complexKeyJSONvsYAML() throws {
let yaml = "? [1, 2]\n: value"
#expect(throws: PureYAML.JSON.Convert.Failure.self) {
_ = try PureYAML.JSON.Convert.convert(yaml, to: .json)
}
let asYAML = try PureYAML.JSON.Convert.convert(yaml, to: .yaml)
#expect(try PureYAML.parse(asYAML) == PureYAML.parse(yaml))
}
}