tablo-macros 0.3.0

Procedural macros for Tablo.
Documentation
use super::*;

fn attrs(source: &str, derive: Derive) -> syn::Result<FormAttrs> {
    let input: syn::DeriveInput = syn::parse_str(source).expect("the derive input parses");
    let syn::Data::Struct(data) = &input.data else {
        panic!("the source declares a struct");
    };
    let field = data
        .fields
        .iter()
        .next()
        .expect("the struct declares a field");
    form_attrs(field, derive)
}

fn refusal(source: &str, derive: Derive) -> String {
    match attrs(source, derive) {
        Ok(_) => String::from("<accepted>"),
        Err(error) => error.to_string(),
    }
}

#[test]
fn embed_marks_an_embedded_value_in_both_derives() {
    for derive in [Derive::Embedded, Derive::Record] {
        assert!(
            attrs("struct F { #[form(embed)] seo: Seo }", derive)
                .unwrap()
                .embed
        );
        assert!(!attrs("struct F { seo: Seo }", derive).unwrap().embed);
    }
}

#[test]
fn a_key_the_derive_does_not_read_is_refused() {
    let message = refusal(
        "struct F { #[form(multiline = 3)] a: String }",
        Derive::Record,
    );
    assert!(message.contains("unknown"), "{message}");
    let message = refusal("struct F { #[form(textarea)] a: String }", Derive::Embedded);
    assert!(message.contains("unknown"), "{message}");
}

#[test]
fn a_control_key_on_an_embedded_value_is_refused() {
    let message = refusal(
        "struct F { #[form(embed, multiline = 3)] seo: Seo }",
        Derive::Embedded,
    );
    assert!(message.contains("embedded value"), "{message}");
    let message = refusal(
        "struct F { #[form(embed, blank = 1)] seo: Seo }",
        Derive::Record,
    );
    assert!(message.contains("embedded value"), "{message}");
}

#[test]
fn a_blank_answer_on_an_option_leaf_is_refused() {
    for derive in [Derive::Embedded, Derive::Record] {
        let message = refusal("struct F { #[form(blank = 0)] a: Option<i64> }", derive);
        assert!(message.contains("`None`"), "{message}");
    }
}

#[test]
fn the_keys_each_derive_reads_are_parsed() {
    let read = attrs(
        r#"struct F { #[form(label = "Body", multiline = 3)] body: String }"#,
        Derive::Embedded,
    )
    .unwrap();
    assert_eq!(read.label.as_deref(), Some("Body"));
    assert_eq!(read.multiline, Some(3));
    for derive in [Derive::Embedded, Derive::Record] {
        let read = attrs("struct F { #[form(blank = 0)] age: i64 }", derive).unwrap();
        assert!(read.blank.is_some());
    }
}