oh_my_toml 0.1.0

Awesome TOML configuration derive macro
Documentation
#![cfg(false)]
//! Tests
#![cfg(test)]

mod common;

use common::item_from_str;
use nonempty::{NonEmpty, nonempty};
use oh_my_toml_macro::OhMyToml;

#[derive(OhMyToml, Debug, PartialEq, Eq)]
struct ConfigTuple(NonEmpty<i32>, (String, u8), [String; 4]);

#[test]
fn it_works() {
    assert_eq!(
        item_from_str::<ConfigTuple>(r#"[[-100, -1000], ["foo", 10], ["a", "b", "c", "d"]]"#)
            .unwrap(),
        ConfigTuple(
            nonempty![-100, -1000],
            ("foo".into(), 10),
            ["a", "b", "c", "d"].map(Into::into)
        )
    );
}

#[test]
fn uses_default_tuple() {
    #[derive(OhMyToml, Default, Debug, PartialEq, Eq)]
    struct A(i32, #[toml(default)] Vec<String>);

    assert_eq!(
        item_from_str::<A>("[100]").unwrap(),
        A(100, vec![]),
        "not present"
    );

    assert_eq!(
        item_from_str::<A>(r#"[100, ["hi", "moon"]] "#).unwrap(),
        A(100, vec!["hi".into(), "moon".into()]),
        "present"
    );
}

#[test]
fn uses_custom_default_tuple() {
    #[derive(OhMyToml, Default, Debug, PartialEq, Eq)]
    struct A(
        i32,
        #[toml(default = vec!["foo".into(), "bar".into()])] Vec<String>,
    );

    assert_eq!(
        item_from_str::<A>(r"[100]").unwrap(),
        A(100, vec!["foo".into(), "bar".into()]),
        "not present"
    );

    assert_eq!(
        item_from_str::<A>(r#"[100, ["hi", "moon"]]"#,).unwrap(),
        A(100, vec!["hi".into(), "moon".into()]),
        "present"
    );
}

#[test]
fn default_all_with_require_tuple() {
    #[derive(OhMyToml, Default, Debug, PartialEq, Eq)]
    #[toml(default_all)]
    struct A(
        #[toml(require)] i32,
        #[toml(default = vec!["foo".into(), "bar".into()])] Vec<String>,
    );

    let oh_my_toml::DeserializeErrors { recovered, errors } = item_from_str::<A>("[]").unwrap_err();

    assert!(
        recovered.is_none(),
        "nothing to recover if a `require`d field is missing"
    );

    assert_eq!(
        errors
            .related()
            .unwrap()
            .map(ToString::to_string)
            .collect::<Vec<_>>(),
        vec!["expected element `0` of type `int`"],
        "not present"
    );

    assert_eq!(
        item_from_str::<A>(r#"[4, ["hi", "moon"]]"#).unwrap(),
        A(4, vec!["hi".into(), "moon".into()]),
        "present"
    );
}

#[test]
fn recover_tuple() {
    #[derive(OhMyToml, Default, Debug, PartialEq, Eq)]
    struct A(#[toml(on_default = "error", default = 4)] i32);

    let oh_my_toml::DeserializeErrors { recovered, errors } = item_from_str::<A>("[]").unwrap_err();

    assert_eq!(recovered, Some(A(4)), "we were able to recover");

    assert_eq!(
        errors
            .related()
            .unwrap()
            .map(ToString::to_string)
            .collect::<Vec<_>>(),
        vec!["expected element `0` of type `int`"],
        "not present"
    );
}

#[test]
fn recover_all_tuple() {
    #[derive(OhMyToml, Default, Debug, PartialEq, Eq)]
    #[toml(on_default_all = "error", default_all)]
    struct A(#[toml(require)] i32, #[toml(default = 1)] i32, i32);

    // We have field 1 (b), but not field 2 (c) which is required
    //
    // We will get an error

    let oh_my_toml::DeserializeErrors { recovered, errors } =
        item_from_str::<A>("[4]").unwrap_err();

    assert_eq!(recovered, Some(A(4, 1, 0)), "we were able to recover");

    assert_eq!(
        errors
            .related()
            .unwrap()
            .map(ToString::to_string)
            .collect::<Vec<_>>(),
        vec![
            "expected element `1` of type `int`",
            "expected element `2` of type `int`"
        ],
        "not present"
    );

    // No field 1 (b), which is `required`
    //
    // Cannot recover.

    let oh_my_toml::DeserializeErrors { recovered, errors } = item_from_str::<A>("[]").unwrap_err();

    assert_eq!(recovered, None, "we were able to recover");

    assert_eq!(
        errors
            .related()
            .unwrap()
            .map(ToString::to_string)
            .collect::<Vec<_>>(),
        vec![
            "expected element `0` of type `int`",
            "expected element `1` of type `int`",
            "expected element `2` of type `int`"
        ],
        "not present"
    );
}