use super::front_matter::json::flatten_json;
use super::front_matter::toml_fm::flatten_toml;
use super::front_matter::yaml::{
collapse_multiline_quoted_scalars, flatten_yaml,
};
use super::*;
use crate::MetadataMap;
use serde_json::Value as JsonValue;
use toml::Value as TomlValue;
#[test]
fn unclosed_multiline_quote_is_emitted_as_is() {
let block = "title: \"\n first part\n second part";
let out = collapse_multiline_quoted_scalars(block);
assert_eq!(out, "title: \"first part second part\n");
}
#[test]
fn closed_multiline_quote_joins_onto_one_line() {
let block = "title: \"\n first\n second\"\nnext: 1";
let out = collapse_multiline_quoted_scalars(block);
assert_eq!(out, "title: \"first second\"\nnext: 1\n");
}
#[test]
fn yaml_flattener_renders_non_string_leaves_and_sequences() {
let value: noyalib::Value = noyalib::from_str(
"count: 3\nflag: true\nnums: [1, 2]\nmixed: [a, 2]",
)
.expect("valid yaml");
let map = flatten_yaml(&value);
assert_eq!(map["count"], "3");
assert_eq!(map["flag"], "true");
assert_eq!(map["nums"], "[1, 2]");
assert_eq!(map["mixed"], "[a, 2]");
}
#[test]
fn toml_flattener_covers_every_leaf_kind() {
let value: TomlValue = toml::from_str(
"name = \"x\"\nn = 7\nok = true\nwhen = 2024-01-02\n\
ints = [1, 2]\nwords = [\"a\", \"b\"]\n[nested]\nk = 1.5",
)
.expect("valid toml");
let mut map = MetadataMap::new();
flatten_toml(&value, &mut map, String::new());
assert_eq!(map["name"], "x");
assert_eq!(map["n"], "7");
assert_eq!(map["ok"], "true");
assert_eq!(map["when"], "2024-01-02");
assert_eq!(map["ints"], "[1, 2]");
assert_eq!(map["words"], "[a, b]");
assert_eq!(map["nested.k"], "1.5");
}
#[test]
fn json_flattener_covers_every_leaf_kind() {
let value: JsonValue = serde_json::from_str(
r#"{"s":"x","n":2,"b":false,"z":null,"arr":[1,"a",null],"o":{"k":{"d":1}}}"#,
)
.expect("valid json");
let mut map = MetadataMap::new();
flatten_json(&value, &mut map, String::new());
assert_eq!(map["s"], "x");
assert_eq!(map["n"], "2");
assert_eq!(map["b"], "false");
assert_eq!(map["z"], "null");
assert_eq!(map["arr"], "[1, a, null]");
assert_eq!(map["o.k.d"], "1");
}
#[test]
fn json_front_matter_syntax_error_is_reported() {
let err = extract_metadata("{\"title\": }").unwrap_err();
assert!(
matches!(
err,
MetadataError::Parse {
format: FrontMatterFormat::Json,
span: Some(ref span),
..
} if span.start == 10
),
"got {err:?}"
);
assert!(err.to_string().contains("expected value"), "got {err}");
}
#[test]
fn json_front_matter_with_nested_objects_and_body() {
let meta = extract_metadata(
"{\"title\": \"T\", \"a\": {\"b\": [1, 2]}}\n\nBody text",
)
.expect("json front matter");
assert_eq!(meta.get("title").map(String::as_str), Some("T"));
assert_eq!(meta.get("a.b").map(String::as_str), Some("[1, 2]"));
}
#[test]
fn dd_mm_yyyy_dates_are_reformatted() {
assert_eq!(
standardize_date("01/02/2024", DateOrder::DayFirst).unwrap(),
"2024-02-01"
);
}
#[test]
fn slash_dates_with_wrong_part_widths_are_rejected() {
let err = standardize_date("123/4/5678", DateOrder::DayFirst)
.unwrap_err();
assert!(
matches!(err, MetadataError::DateParseError(ref m) if m.contains("DD/MM/YYYY"))
);
}
#[test]
fn short_and_empty_dates_are_rejected() {
assert!(
matches!(standardize_date(" ", DateOrder::DayFirst).unwrap_err(), MetadataError::DateParseError(ref m) if m.contains("empty"))
);
assert!(
matches!(standardize_date("2024-1", DateOrder::DayFirst).unwrap_err(), MetadataError::DateParseError(ref m) if m.contains("too short"))
);
assert!(
matches!(standardize_date("2024-99-99", DateOrder::DayFirst).unwrap_err(), MetadataError::DateParseError(ref m) if m.contains("Failed to parse"))
);
}
#[test]
fn process_metadata_standardises_date_and_derives_slug() {
let mut data = MetadataMap::new();
data.insert("title".to_string(), "Hello World!".to_string());
data.insert("date".to_string(), "01/02/2024".to_string());
let out =
process_metadata(&Metadata::new(data)).expect("processed");
assert_eq!(out.get("date").map(String::as_str), Some("2024-02-01"));
assert!(out.contains_key("slug"), "slug derived from title");
assert_eq!(
out.get("slug").map(String::as_str),
Some(&*generate_slug("Hello World!"))
);
}
#[test]
fn process_metadata_keeps_an_explicit_slug() {
let mut data = MetadataMap::new();
data.insert("title".to_string(), "T".to_string());
data.insert("date".to_string(), "2024-02-01".to_string());
data.insert("slug".to_string(), "keep-me".to_string());
let out =
process_metadata(&Metadata::new(data)).expect("processed");
assert_eq!(out.get("slug").map(String::as_str), Some("keep-me"));
}
#[test]
fn process_metadata_reports_a_missing_required_field() {
let mut data = MetadataMap::new();
data.insert("title".to_string(), "T".to_string());
let err = process_metadata(&Metadata::new(data)).unwrap_err();
assert!(
matches!(err, MetadataError::MissingFieldError(ref f) if f == "date")
);
}