use crate::error::MetadataError;
use crate::{
extract_and_prepare_metadata, Keywords, MetaTagGroups, MetadataMap,
};
use std::io::Read;
use std::path::Path;
pub fn extract_from_reader<R: Read>(
mut reader: R,
) -> Result<(MetadataMap, Keywords, MetaTagGroups), MetadataError> {
let mut content = String::new();
reader.read_to_string(&mut content)?;
extract_from_content(&content)
}
pub fn extract_from_file<P: AsRef<Path>>(
path: P,
) -> Result<(MetadataMap, Keywords, MetaTagGroups), MetadataError> {
extract_from_reader(std::fs::File::open(path)?)
}
pub(crate) fn extract_from_content(
content: &str,
) -> Result<(MetadataMap, Keywords, MetaTagGroups), MetadataError> {
if content.trim().is_empty() {
return Ok((
MetadataMap::new(),
Vec::new(),
MetaTagGroups::default(),
));
}
extract_and_prepare_metadata(content)
}
#[cfg(all(test, feature = "yaml"))]
mod tests {
use super::*;
#[test]
fn reader_round_trip_matches_string_api() {
let doc = "---\ntitle: T\ndate: 2024-01-02\n---\nbody";
let via_reader = extract_from_reader(doc.as_bytes()).unwrap();
let direct = extract_and_prepare_metadata(doc).unwrap();
assert_eq!(via_reader.0, direct.0);
assert_eq!(via_reader.1, direct.1);
assert_eq!(via_reader.2, direct.2);
}
#[test]
fn empty_reader_is_empty_metadata() {
let (map, keywords, tags) =
extract_from_reader(b" \n" as &[u8]).unwrap();
assert!(map.is_empty());
assert!(keywords.is_empty());
assert_eq!(tags, MetaTagGroups::default());
}
#[test]
fn invalid_utf8_is_an_io_error() {
let err = extract_from_reader(&[0xff, 0xfe][..]).unwrap_err();
assert!(matches!(err, MetadataError::IoError(_)));
}
#[cfg_attr(
miri,
ignore = "touches the filesystem; Miri isolation forbids it"
)]
#[test]
fn missing_file_is_an_io_error() {
let err =
extract_from_file("/definitely/not/here.md").unwrap_err();
assert!(matches!(err, MetadataError::IoError(_)));
}
}