238 lines
8.0 KiB
Rust
238 lines
8.0 KiB
Rust
use super::{update_frontmatter_content, FrontmatterValue};
|
|
|
|
struct UpdateCase<'a> {
|
|
content: &'a str,
|
|
key: &'a str,
|
|
value: Option<FrontmatterValue>,
|
|
expected_present: &'a [&'a str],
|
|
expected_absent: &'a [&'a str],
|
|
}
|
|
|
|
fn assert_updated_content(case: UpdateCase<'_>) {
|
|
let updated = update_frontmatter_content(case.content, case.key, case.value).unwrap();
|
|
for expected in case.expected_present {
|
|
assert!(
|
|
updated.contains(expected),
|
|
"missing expected snippet: {expected}"
|
|
);
|
|
}
|
|
for unexpected in case.expected_absent {
|
|
assert!(
|
|
!updated.contains(unexpected),
|
|
"found unexpected snippet: {unexpected}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_update_frontmatter_replaces_or_adds_scalar_fields() {
|
|
let cases = [
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "Status",
|
|
value: Some(FrontmatterValue::String("Active".to_string())),
|
|
expected_present: &["Status: Active"],
|
|
expected_absent: &["Status: Draft"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "Owner",
|
|
value: Some(FrontmatterValue::String("Luca".to_string())),
|
|
expected_present: &["Owner: Luca", "Status: Draft"],
|
|
expected_absent: &[],
|
|
},
|
|
UpdateCase {
|
|
content: "---\n\"Is A\": Note\n---\n# Test\n",
|
|
key: "Is A",
|
|
value: Some(FrontmatterValue::String("Project".to_string())),
|
|
expected_present: &["type: Project"],
|
|
expected_absent: &["\"Is A\": Note", "\"Is A\": Project"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "Reviewed",
|
|
value: Some(FrontmatterValue::Bool(true)),
|
|
expected_present: &["Reviewed: true"],
|
|
expected_absent: &[],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "Priority",
|
|
value: Some(FrontmatterValue::Number(5.0)),
|
|
expected_present: &["Priority: 5"],
|
|
expected_absent: &[],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "Score",
|
|
value: Some(FrontmatterValue::Number(9.5)),
|
|
expected_present: &["Score: 9.5"],
|
|
expected_absent: &[],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "ClearMe",
|
|
value: Some(FrontmatterValue::Null),
|
|
expected_present: &["ClearMe: null"],
|
|
expected_absent: &[],
|
|
},
|
|
];
|
|
|
|
for case in cases {
|
|
assert_updated_content(case);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_update_frontmatter_list_and_delete_paths() {
|
|
let list_cases = [
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "aliases",
|
|
value: Some(FrontmatterValue::List(vec![
|
|
"Alias1".to_string(),
|
|
"Alias2".to_string(),
|
|
])),
|
|
expected_present: &["aliases:", " - \"Alias1\"", " - \"Alias2\""],
|
|
expected_absent: &[],
|
|
},
|
|
UpdateCase {
|
|
content: "---\naliases:\n - Old1\n - Old2\nStatus: Draft\n---\n# Test\n",
|
|
key: "aliases",
|
|
value: Some(FrontmatterValue::List(vec!["New1".to_string()])),
|
|
expected_present: &[" - \"New1\"", "Status: Draft"],
|
|
expected_absent: &["Old1", "Old2"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\naliases:\n - Alias1\n - Alias2\nStatus: Draft\n---\n# Test\n",
|
|
key: "aliases",
|
|
value: None,
|
|
expected_present: &["Status: Draft"],
|
|
expected_absent: &["aliases", "Alias1"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\nOwner: Luca\n---\n# Test\n",
|
|
key: "Owner",
|
|
value: None,
|
|
expected_present: &["Status: Draft"],
|
|
expected_absent: &["Owner"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nStatus: Draft\n---\n# Test\n",
|
|
key: "tags",
|
|
value: Some(FrontmatterValue::List(vec![])),
|
|
expected_present: &["tags: []"],
|
|
expected_absent: &[],
|
|
},
|
|
];
|
|
|
|
for case in list_cases {
|
|
assert_updated_content(case);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_update_frontmatter_handles_missing_or_malformed_frontmatter() {
|
|
let inserted = update_frontmatter_content(
|
|
"# Test\n\nSome content here.",
|
|
"Status",
|
|
Some(FrontmatterValue::String("Draft".to_string())),
|
|
)
|
|
.unwrap();
|
|
assert!(inserted.starts_with("---\n"));
|
|
assert!(inserted.contains("Status: Draft"));
|
|
assert!(inserted.contains("# Test"));
|
|
|
|
let malformed = update_frontmatter_content(
|
|
"---\nStatus: Draft\nNo closing fence here",
|
|
"Status",
|
|
Some(FrontmatterValue::String("Active".to_string())),
|
|
);
|
|
assert!(malformed.is_err());
|
|
assert!(malformed.unwrap_err().contains("Malformed frontmatter"));
|
|
|
|
let unchanged =
|
|
update_frontmatter_content("---\nStatus: Draft\n---\n# Test\n", "Missing", None).unwrap();
|
|
assert_eq!(unchanged, "---\nStatus: Draft\n---\n# Test\n");
|
|
|
|
let no_frontmatter =
|
|
update_frontmatter_content("# Test\n\nSome content.", "Missing", None).unwrap();
|
|
assert_eq!(no_frontmatter, "# Test\n\nSome content.");
|
|
}
|
|
|
|
#[test]
|
|
fn test_update_frontmatter_canonicalizes_system_metadata_keys() {
|
|
let cases = [
|
|
UpdateCase {
|
|
content: "---\narchived: false\n---\n# Test\n",
|
|
key: "_archived",
|
|
value: Some(FrontmatterValue::Bool(true)),
|
|
expected_present: &["_archived: true"],
|
|
expected_absent: &["archived: false"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nicon: rocket\n---\n# Test\n",
|
|
key: "icon",
|
|
value: Some(FrontmatterValue::String("star".to_string())),
|
|
expected_present: &["_icon: star"],
|
|
expected_absent: &["\nicon:", "rocket"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nsidebar label: Projects\nsidebar_label: Legacy\n---\n# Test\n",
|
|
key: "_sidebar_label",
|
|
value: Some(FrontmatterValue::String("Programs".to_string())),
|
|
expected_present: &["_sidebar_label: Programs"],
|
|
expected_absent: &["sidebar label: Projects", "sidebar_label: Legacy"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nsort: modified:desc\n_sort: title:asc\n---\n# Test\n",
|
|
key: "_sort",
|
|
value: None,
|
|
expected_present: &["# Test"],
|
|
expected_absent: &["\nsort:", "\n_sort:"],
|
|
},
|
|
];
|
|
|
|
for case in cases {
|
|
assert_updated_content(case);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_update_frontmatter_canonicalizes_type_key_case() {
|
|
let cases = [
|
|
UpdateCase {
|
|
content: "---\nType: Note\n---\n# Test\n",
|
|
key: "type",
|
|
value: Some(FrontmatterValue::String("Project".to_string())),
|
|
expected_present: &["type: Project"],
|
|
expected_absent: &["Type: Note"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\n\"Is A\": Note\nis_a: Topic\n---\n# Test\n",
|
|
key: "type",
|
|
value: Some(FrontmatterValue::String("Project".to_string())),
|
|
expected_present: &["type: Project"],
|
|
expected_absent: &["\"Is A\": Note", "is_a: Topic"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nTYPE: Note\n---\n# Test\n",
|
|
key: "Type",
|
|
value: Some(FrontmatterValue::String("Person".to_string())),
|
|
expected_present: &["type: Person"],
|
|
expected_absent: &["TYPE: Note"],
|
|
},
|
|
UpdateCase {
|
|
content: "---\nType: Note\nstatus: Active\n---\n# Test\n",
|
|
key: "type",
|
|
value: None,
|
|
expected_present: &["status: Active", "# Test"],
|
|
expected_absent: &["Type: Note", "\ntype:"],
|
|
},
|
|
];
|
|
|
|
for case in cases {
|
|
assert_updated_content(case);
|
|
}
|
|
}
|