use crate::document::Document;
fn ambiguous_strings_fixture() -> String {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let path = std::path::Path::new(manifest_dir)
.join("..")
.join("fixtures")
.join("resources")
.join("ambiguous_strings.md");
std::fs::read_to_string(&path).unwrap_or_else(|e| {
panic!(
"Cannot read ambiguous_strings.md at {}: {}",
path.display(),
e
)
})
}
fn parse_fixture() -> Document {
let src = ambiguous_strings_fixture();
Document::from_markdown(&src)
.unwrap_or_else(|e| panic!("ambiguous_strings.md failed to parse: {}", e))
}
fn assert_string_field_round_trips(doc: &Document, key: &str, expected: &str) {
let value = doc
.main()
.frontmatter()
.get(key)
.unwrap_or_else(|| panic!("field '{}' not found in frontmatter", key));
assert!(
value.as_str().is_some(),
"field '{}': expected QuillValue::String, got {:?}",
key,
value
);
assert_eq!(
value.as_str().unwrap(),
expected,
"field '{}': string value mismatch",
key
);
}
fn assert_round_trip_strings(keys_and_values: &[(&str, &str)]) {
let doc = parse_fixture();
let emitted = doc.to_markdown();
let doc2 = Document::from_markdown(&emitted)
.unwrap_or_else(|e| panic!("re-parse after emit failed: {}\nEmitted:\n{}", e, emitted));
for (key, expected) in keys_and_values {
assert_string_field_round_trips(&doc, key, expected);
let v2 = doc2
.main()
.frontmatter()
.get(*key)
.unwrap_or_else(|| panic!("field '{}' missing after round-trip", key));
assert!(
v2.as_str().is_some(),
"field '{}' is not a string after round-trip; value = {:?}",
key,
v2
);
assert_eq!(
v2.as_str().unwrap(),
*expected,
"field '{}': value changed on round-trip",
key
);
}
}
#[test]
fn ambiguous_word_booleans_round_trip() {
assert_round_trip_strings(&[
("on_word", "on"),
("off_word", "off"),
("yes_word", "yes"),
("no_word", "no"),
("true_word", "true"),
("false_word", "false"),
]);
}
#[test]
fn ambiguous_null_like_round_trip() {
assert_round_trip_strings(&[("null_word", "null"), ("tilde", "~")]);
}
#[test]
fn ambiguous_numeric_like_round_trip() {
assert_round_trip_strings(&[
("leading_zeros", "01234"),
("exponential", "1e10"),
("hex_like", "0x1F"),
]);
}
#[test]
fn ambiguous_iso_date_round_trip() {
assert_round_trip_strings(&[("iso_date", "2024-01-15")]);
}
#[test]
fn ambiguous_special_characters_round_trip() {
assert_round_trip_strings(&[
("empty_string", ""),
("single_space", " "),
("embedded_newline", "line1\nline2"),
("embedded_quote", "he said \"hi\""),
("embedded_backslash", "a\\b"),
]);
}
#[test]
fn ambiguous_yaml_syntax_round_trip() {
assert_round_trip_strings(&[
("looks_like_map", "key: value"),
("looks_like_seq", "- item"),
("hash_comment", "#comment"),
("yaml_anchor", "&anchor"),
("yaml_alias", "*alias"),
("yaml_tag", "!tag"),
]);
}
#[test]
fn all_ambiguous_fields_are_strings() {
let doc = parse_fixture();
let expected_string_fields = [
"on_word",
"off_word",
"yes_word",
"no_word",
"true_word",
"false_word",
"null_word",
"tilde",
"leading_zeros",
"exponential",
"hex_like",
"iso_date",
"empty_string",
"single_space",
"embedded_newline",
"embedded_quote",
"embedded_backslash",
"looks_like_map",
"looks_like_seq",
"hash_comment",
"yaml_anchor",
"yaml_alias",
"yaml_tag",
];
for field in &expected_string_fields {
let value = doc
.main()
.frontmatter()
.get(*field)
.unwrap_or_else(|| panic!("field '{}' not found", field));
assert!(
value.as_str().is_some(),
"field '{}' must be QuillValue::String, got {:?}",
field,
value
);
}
}