2024-06-13 20:37:56 +00:00
|
|
|
use saphyr::{Yaml, YamlEmitter};
|
2023-08-18 00:04:21 +00:00
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
/// Test in sequence the parser, emitter and parser with the given input.
|
|
|
|
///
|
|
|
|
/// 1. Pass the input through the loader and build a YAML object from it.
|
|
|
|
/// 2. Pass the newly created YAML object through the emitter.
|
|
|
|
/// 3. Pass the emitted string through the loader and build another YAML object from it.
|
|
|
|
/// 4. Assert that the YAML objects from 1. and 3. are the same.
|
|
|
|
/// 5. Return the string from 3. so the caller can ensure its formatting.
|
|
|
|
///
|
|
|
|
/// The assertion done in this function is purely on the contents of the YAML objects and not on
|
|
|
|
/// its presentation.
|
|
|
|
///
|
|
|
|
/// This function additionally prints to stdout the input string and the resulting string from 2..
|
|
|
|
///
|
|
|
|
/// The configuration function `config` allows the caller to potentially change some settings in
|
|
|
|
/// the emitter prior to emitting.
|
|
|
|
fn raw_roundtrip<Config: FnOnce(&mut YamlEmitter)>(input: &str, config: Config) -> String {
|
|
|
|
let original_docs = Yaml::load_from_str(input).unwrap();
|
|
|
|
let original_doc = &original_docs[0];
|
|
|
|
let mut emitted_string = String::new();
|
|
|
|
{
|
|
|
|
let mut emitter = YamlEmitter::new(&mut emitted_string);
|
|
|
|
config(&mut emitter);
|
|
|
|
emitter.dump(original_doc).unwrap();
|
|
|
|
}
|
|
|
|
println!("original:\n{input}");
|
|
|
|
println!("emitted:\n{emitted_string}");
|
|
|
|
|
|
|
|
let emitted_docs = Yaml::load_from_str(&emitted_string).unwrap();
|
|
|
|
assert_eq!(original_docs, emitted_docs);
|
|
|
|
|
|
|
|
emitted_string
|
|
|
|
}
|
|
|
|
|
|
|
|
/// [`raw_roundtrip`] with default configuration
|
|
|
|
fn roundtrip(input: &str) -> String {
|
|
|
|
raw_roundtrip(input, |_| {})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like [`roundtrip`] but with the [compact flag] disabled.
|
|
|
|
///
|
|
|
|
/// [compact flag]: `YamlEmitter::compact`
|
|
|
|
fn roundtrip_not_compact(input: &str) -> String {
|
|
|
|
raw_roundtrip(input, |emitter| emitter.compact(false))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Like [`roundtrip`] but with the [multiline strings flag] enabled.
|
|
|
|
///
|
|
|
|
/// [multiline strings flag]: `YamlEmitter::multiline_strings`
|
|
|
|
fn roundtrip_multiline(input: &str) -> String {
|
|
|
|
raw_roundtrip(input, |emitter| emitter.multiline_strings(true))
|
|
|
|
}
|
|
|
|
|
2023-08-18 00:04:21 +00:00
|
|
|
#[allow(clippy::similar_names)]
|
|
|
|
#[test]
|
|
|
|
fn test_emit_simple() {
|
|
|
|
let s = "
|
|
|
|
# comment
|
|
|
|
a0 bb: val
|
|
|
|
a1:
|
|
|
|
b1: 4
|
|
|
|
b2: d
|
|
|
|
a2: 4 # i'm comment
|
|
|
|
a3: [1, 2, 3]
|
|
|
|
a4:
|
|
|
|
- [a1, a2]
|
|
|
|
- 2
|
|
|
|
";
|
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
roundtrip(s);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_emit_complex() {
|
2024-02-13 22:10:17 +00:00
|
|
|
let s = r"
|
2024-03-25 11:01:58 +00:00
|
|
|
catalogue:
|
2023-08-18 00:04:21 +00:00
|
|
|
product: &coffee { name: Coffee, price: 2.5 , unit: 1l }
|
|
|
|
product: &cookies { name: Cookies!, price: 3.40 , unit: 400g}
|
|
|
|
|
|
|
|
products:
|
|
|
|
*coffee :
|
|
|
|
amount: 4
|
|
|
|
*cookies :
|
|
|
|
amount: 4
|
|
|
|
[1,2,3,4]:
|
|
|
|
array key
|
|
|
|
2.4:
|
|
|
|
real key
|
|
|
|
true:
|
|
|
|
bool key
|
|
|
|
{}:
|
|
|
|
empty hash key
|
2024-02-13 22:10:17 +00:00
|
|
|
";
|
2024-11-28 01:39:29 +00:00
|
|
|
|
|
|
|
roundtrip(s);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_emit_avoid_quotes() {
|
|
|
|
let s = r#"---
|
|
|
|
a7: 你好
|
|
|
|
boolean: "true"
|
|
|
|
boolean2: "false"
|
|
|
|
date: 2014-12-31
|
|
|
|
empty_string: ""
|
|
|
|
empty_string1: " "
|
|
|
|
empty_string2: " a"
|
|
|
|
empty_string3: " a "
|
|
|
|
exp: "12e7"
|
|
|
|
field: ":"
|
|
|
|
field2: "{"
|
|
|
|
field3: "\\"
|
|
|
|
field4: "\n"
|
|
|
|
field5: "can't avoid quote"
|
|
|
|
float: "2.6"
|
|
|
|
int: "4"
|
|
|
|
nullable: "null"
|
|
|
|
nullable2: "~"
|
|
|
|
products:
|
|
|
|
"*coffee":
|
|
|
|
amount: 4
|
|
|
|
"*cookies":
|
|
|
|
amount: 4
|
|
|
|
".milk":
|
|
|
|
amount: 1
|
|
|
|
"2.4": real key
|
|
|
|
"[1,2,3,4]": array key
|
|
|
|
"true": bool key
|
|
|
|
"{}": empty hash key
|
|
|
|
x: test
|
|
|
|
y: avoid quoting here
|
|
|
|
z: string with spaces"#;
|
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
assert_eq!(roundtrip(s), s);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn emit_quoted_bools() {
|
|
|
|
let input = r#"---
|
|
|
|
string0: yes
|
|
|
|
string1: no
|
|
|
|
string2: "true"
|
|
|
|
string3: "false"
|
|
|
|
string4: "~"
|
|
|
|
null0: ~
|
|
|
|
[true, false]: real_bools
|
|
|
|
[True, TRUE, False, FALSE, y,Y,yes,Yes,YES,n,N,no,No,NO,on,On,ON,off,Off,OFF]: false_bools
|
|
|
|
bool0: true
|
|
|
|
bool1: false"#;
|
|
|
|
let expected = r#"---
|
|
|
|
string0: "yes"
|
|
|
|
string1: "no"
|
|
|
|
string2: "true"
|
|
|
|
string3: "false"
|
|
|
|
string4: "~"
|
|
|
|
null0: ~
|
|
|
|
? - true
|
|
|
|
- false
|
|
|
|
: real_bools
|
|
|
|
? - "True"
|
|
|
|
- "TRUE"
|
|
|
|
- "False"
|
|
|
|
- "FALSE"
|
|
|
|
- y
|
|
|
|
- Y
|
|
|
|
- "yes"
|
|
|
|
- "Yes"
|
|
|
|
- "YES"
|
|
|
|
- n
|
|
|
|
- N
|
|
|
|
- "no"
|
|
|
|
- "No"
|
|
|
|
- "NO"
|
|
|
|
- "on"
|
|
|
|
- "On"
|
|
|
|
- "ON"
|
|
|
|
- "off"
|
|
|
|
- "Off"
|
|
|
|
- "OFF"
|
|
|
|
: false_bools
|
|
|
|
bool0: true
|
|
|
|
bool1: false"#;
|
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
assert_eq!(roundtrip(input), expected);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-11-28 01:39:29 +00:00
|
|
|
fn test_empty_and_nested_not_compact() {
|
|
|
|
let s = r"---
|
2023-08-18 00:04:21 +00:00
|
|
|
a:
|
|
|
|
b:
|
|
|
|
c: hello
|
|
|
|
d: {}
|
|
|
|
e:
|
|
|
|
- f
|
|
|
|
- g
|
2024-11-28 01:39:29 +00:00
|
|
|
-
|
|
|
|
h: []";
|
|
|
|
assert_eq!(roundtrip_not_compact(s), s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_empty_and_nested_compact() {
|
|
|
|
let s = r"---
|
2023-08-18 00:04:21 +00:00
|
|
|
a:
|
|
|
|
b:
|
|
|
|
c: hello
|
|
|
|
d: {}
|
|
|
|
e:
|
|
|
|
- f
|
|
|
|
- g
|
2024-11-28 01:39:29 +00:00
|
|
|
- h: []";
|
|
|
|
assert_eq!(roundtrip(s), s);
|
|
|
|
}
|
2023-08-18 00:04:21 +00:00
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
#[test]
|
|
|
|
fn test_interleaved_mappings_and_sequences() {
|
|
|
|
let input = r"---
|
|
|
|
a:
|
|
|
|
- b:
|
|
|
|
- c: d";
|
|
|
|
assert_eq!(roundtrip(input), input);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_nested_arrays() {
|
2024-02-13 22:10:17 +00:00
|
|
|
let s = r"---
|
2023-08-18 00:04:21 +00:00
|
|
|
a:
|
|
|
|
- b
|
|
|
|
- - c
|
|
|
|
- d
|
|
|
|
- - e
|
2024-02-13 22:10:17 +00:00
|
|
|
- f";
|
2024-11-28 01:39:29 +00:00
|
|
|
assert_eq!(roundtrip(s), s);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deeply_nested_arrays() {
|
2024-02-13 22:10:17 +00:00
|
|
|
let s = r"---
|
2023-08-18 00:04:21 +00:00
|
|
|
a:
|
|
|
|
- b
|
|
|
|
- - c
|
|
|
|
- d
|
|
|
|
- - e
|
|
|
|
- - f
|
2024-02-13 22:10:17 +00:00
|
|
|
- - e";
|
2024-11-28 01:39:29 +00:00
|
|
|
assert_eq!(roundtrip(s), s);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_nested_hashes() {
|
2024-02-13 22:10:17 +00:00
|
|
|
let s = r"---
|
2023-08-18 00:04:21 +00:00
|
|
|
a:
|
|
|
|
b:
|
|
|
|
c:
|
|
|
|
d:
|
2024-02-13 22:10:17 +00:00
|
|
|
e: f";
|
2024-11-28 01:39:29 +00:00
|
|
|
assert_eq!(roundtrip(s), s);
|
|
|
|
}
|
2023-08-18 00:04:21 +00:00
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
#[test]
|
|
|
|
fn test_empty_sequence() {
|
|
|
|
let s = r"---
|
|
|
|
[]";
|
|
|
|
assert_eq!(roundtrip(s), s);
|
|
|
|
}
|
2023-08-18 00:04:21 +00:00
|
|
|
|
2024-11-28 01:39:29 +00:00
|
|
|
#[test]
|
|
|
|
fn test_empty_mapping() {
|
|
|
|
let s = r"---
|
|
|
|
{}";
|
|
|
|
assert_eq!(roundtrip(s), s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_root_sequence() {
|
|
|
|
let s = r"---
|
|
|
|
- a";
|
|
|
|
assert_eq!(roundtrip(s), s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_root_mapping() {
|
|
|
|
let s = r"---
|
|
|
|
a: b";
|
|
|
|
assert_eq!(roundtrip(s), s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_multiline_string() {
|
|
|
|
let input = r#"{foo: "bar!\nbar!", baz: 42}"#;
|
|
|
|
let expected = r"---
|
|
|
|
foo: |-
|
|
|
|
bar!
|
|
|
|
bar!
|
|
|
|
baz: 42";
|
|
|
|
assert_eq!(roundtrip_multiline(input), expected);
|
2023-08-18 00:04:21 +00:00
|
|
|
}
|