microformats 0.18.2

A union library of the Microformats types and associated parser.
Documentation
use super::*;
use crate::parse::{
    ElementRef,
    element::test::{from_html_str, grab_element_from_document},
};
use microformats_types::{TextValue, UrlValue};
use tracing_unwrap::OptionExt;

#[yare::parameterized(
    simple = {
        r#"<img class="h-card" alt="wow" src="/photo.jpg" />"#, "img",
        Some(PropertyValue::Image(Image {
            value: "http://example.com/photo.jpg".parse()?,
            alt: Some("wow".to_string()),
        }))
    },
    hcard_impliedphoto_only_of_child = {
        r#"
<div class="h-card"><span><img alt="Jane Doe" src="jane.jpeg"/></span></div>
        "#, "div",
        Some(PropertyValue::Image(Image {
            value: "http://example.com/jane.jpeg".parse()?,
            alt: Some("Jane Doe".to_string()),
        }))
    },
    hcard_multiple_photos = {
        r#"
<div class="h-card"> <a href="https://example.com" class="p-name u-url">John Doe <img src="https://example.com/photo.jpg" alt=""> <img src="https://example.com/photo2.jpg" alt=""></a> </div>
        "#, "div", None
    },
    hcard_pproperty = {
        r#"
<div class="h-card">
    <img class="p-honorific-suffix" src="images/logo.gif" alt="PHD" />
    <img src="images/logo.gif" alt="company logos" usemap="\#logomap" />
</div>
        "#, "div", None
    }

)]
fn photo(html: &str, tag: &str, value: Option<PropertyValue>) -> Result<(), crate::Error> {
    let base_url: url::Url = "http://example.com".parse()?;
    let elem = grab_element_from_document(&from_html_str(html), tag).unwrap_or_log();

    let parser = ImpliedPhotoExtractor(Arc::new(ElementRef {
        index: 0,
        node: Node { elem },
    }));

    assert!(
        ImpliedPhotoExtractor::can_extract(&Default::default()),
        "can expect to get an implied photo"
    );

    assert_eq!(parser.extract(&base_url), value, "implied a photo");
    Ok(())
}

#[yare::parameterized(
    should_imply = { true, Properties::default() },
    p_prop = { false, Properties::from_iter(vec![
        ("name".to_string(), vec![PropertyValue::Plain(TextValue::new("existing".to_string()))])
    ])},
    e_prop = { false, Properties::from_iter(vec![
        ("name".to_string(), vec![
            PropertyValue::Fragment(Fragment {
                html: "Implied name.".to_string(),
                value: "Implied name.".to_string(),
                ..Default::default()
            })
        ])
    ])},
    nested_prop = { false, Properties::from_iter(vec![
        ("like-of".to_string(), vec![
            PropertyValue::Item(Item {
                r#type: vec![microformats_types::KnownClass::Cite.into()],
                ..Default::default()
            })
        ])
    ])},
)]
fn can_imply_name(assertion: bool, props: Properties) {
    assert_eq!(ImpliedNameExtractor::can_extract(&props), assertion);
}

#[yare::parameterized(
    img_alt    = {"img",  r#"<img class="h-card" alt="The implied name." />"#},
    abbr_title = {"abbr", r#"<abbr class="h-card" title="The implied name.">Not this.</abbr>"#},
    direct_img_alt    = {"span", r#"<img alt="The implied name." />"#},
    direct_area_alt   = {"span", r#"<area alt="The implied name."></area>"#},
    direct_abbr_title = {"span", r#"<abbr title="The implied name.">Not this.</abbr>"#},
    nested_direct_img_alt    = {"div", r#"<img alt="The implied name." />"#},
    nested_direct_area_alt   = {"div", r#"<area alt="The implied name."></abbr>"#},
    nested_direct_abbr_title = {"div", r#"<abbr title="The implied name.">Not this.</abbr>"#},
    weird_embed = {"p", r#"
<!-- drop nested <script> and <style>, replace <img> with alt -->
<p class="h-card"><style>p{font-color: red;}</style> <span>The</span> <span>implied</span><script src="https://example.com/script.js"></script> <img src="/photo.jpg" alt="name."> </p>
    "#}
)]
fn name(tag: &str, html: &str) {
    let base_url = "http://example.com".parse().unwrap();
    let full_html = match tag {
        "span" => format!(r#"<span class='h-card'>{html}</span>"#),
        "div" => format!(r#"<div class='h-card'><span>{html}</span></div>"#),
        _ => html.to_string(),
    };
    let direct_parser = ImpliedNameExtractor(Arc::new(ElementRef {
        index: 0,
        node: Node {
            elem: grab_element_from_document(&from_html_str(&full_html), tag).unwrap_or_log(),
        },
    }));

    assert_eq!(
        direct_parser.extract(&base_url),
        Some(PropertyValue::Plain(TextValue::new(
            "The implied name.".to_string()
        ))),
        "implied a name directly"
    );
}

#[test]
fn url() -> Result<(), crate::Error> {
    let dom = from_html_str(r#"<div class="h-item"><a class="h-item" href="/"></a></div>"#);
    let parent_elem = grab_element_from_document(&dom, "div").unwrap_or_log();

    let parent_parser = PropertiesParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem: parent_elem },
        }),
        Default::default(),
        &"http://example.com".parse()?,
    );

    assert!(
        parent_parser.can_imply_url(),
        "can expect to get an implied URL"
    );

    assert_eq!(parent_parser.implied_url(), None, "did not imply a URL");

    let child_elem = grab_element_from_document(&dom, "a").unwrap_or_log();

    let child_parser = PropertiesParser::new(
        Arc::new(ElementRef {
            index: 0,
            node: Node { elem: child_elem },
        }),
        Default::default(),
        &"http://example.com".parse()?,
    );

    assert!(
        child_parser.can_imply_url(),
        "can expect to get an implied URL"
    );

    assert_eq!(
        child_parser.implied_url(),
        Some(PropertyValue::Url(UrlValue::new(
            "http://example.com/".parse()?
        ))),
        "implied a URL"
    );

    Ok(())
}