The emitter kept its own list of reserved words and number shapes, apart from the parser's, and the two disagreed: the string yes was written plain and read back as a boolean, as were 0x1F, 1_000 and .inf. The parser's reading of a plain scalar is now one type that both use, and the emitter quotes what does not read back as a string. Also quoted: the merge key, the document end marker, and a string with a CR+LF break, which was written raw.
57 lines
3.3 KiB
Swift
57 lines
3.3 KiB
Swift
@testable import PureYAML
|
||
import Testing
|
||
|
||
/// A string the emitter writes without quotes must be read back as that same string. The parser decides what a plain word means (a boolean, a number, null,
|
||
/// or a string), so the emitter quotes every string the parser would read as anything else.
|
||
@Suite("Plain scalar round trip")
|
||
struct PlainScalarRoundTripTests {
|
||
/// Words and shapes that a reader may take for something other than a string, and shapes that break plain syntax.
|
||
static let corpus: [String] = [
|
||
"yes", "Yes", "YES", "no", "No", "NO", "on", "On", "ON", "off", "Off", "OFF", "y", "n", "Y", "N", "true", "True", "TRUE", "false", "False", "FALSE",
|
||
"null", "Null", "NULL", "~", "0", "-0", "+0", "1", "+1", "-1", "017", "0123", "0o17", "0O17", "0x1F", "0X1f", "0b101", "0B1", "-0x1F", "+0x1F", "1_000",
|
||
"1__0", "0_1", "_1", "1_", "1e3", "1E3", "1e+3", "1.5", "1.", ".5", "-.5", "+.5", ".inf", ".Inf", ".INF", "-.inf", "+.inf", ".nan", ".NaN", ".NAN", "inf",
|
||
"nan", "Infinity", "1e400", "0x", "0b", "0o", "9223372036854775807", "9223372036854775808", "-9223372036854775808", "12345678901234567890",
|
||
"2001-01-01", "12:30:45", "1:30", "<<", "=", "---", "...", "?", "- x", "-", "a: b", "a:", "a :", ":a", "#c", "a #c", "x#c", "!x", "&a", "*a", "|", ">",
|
||
"%x", "@x", "`x", "'x", "\"x", " x", "x ", "a\tb", "a\nb", "a\r\nb", "héllo", "✓", "a,b", "[a]", "{a}", "a]", "k: v", "x:y", "x: ", "", " ", "word",
|
||
"two words", "a-b", "a?b", "?x", "-x", "- ", "1 2", "1e", "e1", ".", "..", "+", "0.", "00", "0e0", "1_0.5", "١٢٣", "٣.٥",
|
||
]
|
||
|
||
private static let styles: [PureYAML.Emitting.CollectionStyle] = [.block, .flow]
|
||
|
||
private func roundTrip(_ value: PureYAML.Model.Value, _ style: PureYAML.Emitting.CollectionStyle) throws -> PureYAML.Model.Value {
|
||
let yaml = PureYAML.dump(value, options: .init(scalarStyle: .plainWhenSafe, collectionStyle: style))
|
||
return try PureYAML.parse(yaml)
|
||
}
|
||
|
||
@Test("A string at the root reads back as itself", arguments: corpus)
|
||
func root(text: String) throws {
|
||
for style in Self.styles {
|
||
#expect(try roundTrip(.string(text), style) == .string(text), "\(style): \(text.debugDescription)")
|
||
}
|
||
}
|
||
|
||
@Test("A string as a mapping value reads back as itself", arguments: corpus)
|
||
func mappingValue(text: String) throws {
|
||
let value = PureYAML.Model.Value.mapping(.init([.init(key: "k", value: .string(text))]))
|
||
for style in Self.styles {
|
||
#expect(try roundTrip(value, style) == value, "\(style): \(text.debugDescription)")
|
||
}
|
||
}
|
||
|
||
@Test("A string as a mapping key reads back as itself", arguments: corpus)
|
||
func mappingKey(text: String) throws {
|
||
let value = PureYAML.Model.Value.mapping(.init([.init(key: text, value: .int(1))]))
|
||
for style in Self.styles {
|
||
#expect(try roundTrip(value, style) == value, "\(style): \(text.debugDescription)")
|
||
}
|
||
}
|
||
|
||
@Test("A string in a sequence reads back as itself", arguments: corpus)
|
||
func sequenceItem(text: String) throws {
|
||
let value = PureYAML.Model.Value.sequence([.string(text), .string("after")])
|
||
for style in Self.styles {
|
||
#expect(try roundTrip(value, style) == value, "\(style): \(text.debugDescription)")
|
||
}
|
||
}
|
||
}
|