#![deny(unsafe_code)]
#![no_implicit_prelude]

use ::quote::quote as q;

mod test_util;
use test_util::*;

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyUnit;

#[test]
fn parse_unit() {
    let parse = parse_meta::<MyUnit>;
    ::std::assert_eq!(parse(q! { () }).unwrap(), MyUnit);
    ::std::assert_eq!(
        parse(q! { (1) }).unwrap_err_string(),
        "unexpected token `1`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyUnnamedEmpty();

#[test]
fn parse_unnamed_empty() {
    let parse = parse_meta::<MyUnnamedEmpty>;
    ::std::assert_eq!(parse(q! { () }).unwrap(), MyUnnamedEmpty());
    ::std::assert_eq!(
        parse(q! { (1) }).unwrap_err_string(),
        "unexpected token `1`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent)]
struct MyNewtype(::std::string::String);

#[test]
fn parse_newtype() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyNewtype>;

    ::std::assert_eq!(parse(q! { "qwerty" }).unwrap(), MyNewtype("qwerty".into()));
    ::std::assert_eq!(
        parse(q! { 123 }).unwrap_err_string(),
        "expected string literal"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyUnnamed(i32, ::std::string::String);

#[test]
fn parse_unnamed() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyUnnamed>;

    ::std::assert_eq!(
        parse(q! { (123, "abc") }).unwrap(),
        MyUnnamed(123, "abc".into())
    );
    ::std::assert_eq!(
        parse(q! { (123) }).unwrap_err_string(),
        "missing required field 1"
    );
    ::std::assert_eq!(
        parse(q! { (123, "abc", true) }).unwrap_err_string(),
        "unexpected token `true`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyNamedEmpty {}

#[test]
fn parse_named_empty() {
    let parse = parse_meta::<MyNamedEmpty>;

    ::std::assert_eq!(parse(q! { {} }).unwrap(), MyNamedEmpty {});
    ::std::assert_eq!(
        parse(q! { {a = 123} }).unwrap_err_string(),
        "unknown field `a`"
    );

    ::std::assert_eq!(parse_flag::<MyNamedEmpty>().unwrap(), MyNamedEmpty {});
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyNamed {
    a: i32,
    b: ::std::string::String,
}

#[test]
fn parse_named() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyNamed>;

    let t = MyNamed {
        a: 123,
        b: "asdf".into(),
    };
    ::std::assert_eq!(parse(q! { {a = 123, b = "asdf"} }).unwrap(), t);
    ::std::assert_eq!(parse(q! { {a(123), b = "asdf"} }).unwrap(), t);
    ::std::assert_eq!(parse(q! { {a = 123, b("asdf")} }).unwrap(), t);
    ::std::assert_eq!(parse(q! { {a(123), b("asdf")} }).unwrap(), t);

    ::std::assert_eq!(
        parse(q! { {} }).unwrap_err_string(),
        "missing required field `a`, missing required field `b`"
    );
    ::std::assert_eq!(
        parse(q! { {b("asdf")} }).unwrap_err_string(),
        "missing required field `a`"
    );
    ::std::assert_eq!(
        parse(q! { {a(123)} }).unwrap_err_string(),
        "missing required field `b`"
    );
    ::std::assert_eq!(
        parse(q! { {a(123), b("asdf"), c(true)} }).unwrap_err_string(),
        "unknown field `c`"
    );
    ::std::assert_eq!(
        parse(q! { {a(123), b("asdf"), a(456)} }).unwrap_err_string(),
        "duplicate attribute for `a`"
    );
    ::std::assert_eq!(
        parse(q! { {a(123), b("asdf"), a(456), a("456") } }).unwrap_err_string(),
        "duplicate attribute for `a`, duplicate attribute for `a`, expected integer literal"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyNamedChild {
    c: i32,
    #[deluxe(flatten)]
    d: MyNamed,
}

#[test]
fn parse_named_flat() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyNamedChild>;

    let t = MyNamedChild {
        c: 900,
        d: MyNamed {
            a: 100,
            b: "qwerty".into(),
        },
    };
    ::std::assert_eq!(parse(q! { {a = 100, b = "qwerty", c = 900} }).unwrap(), t);
    ::std::assert_eq!(
        parse(q! { {} }).unwrap_err_string(),
        "missing required field `a`, missing required field `b`, missing required field `c`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyNamedChildPrefixed {
    c: i32,
    #[deluxe(flatten(prefix = d))]
    d: MyNamed,
}

#[test]
fn parse_named_flat_prefixed() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyNamedChildPrefixed>;

    let t = MyNamedChildPrefixed {
        c: 900,
        d: MyNamed {
            a: 100,
            b: "qwerty".into(),
        },
    };
    ::std::assert_eq!(
        parse(q! { {d::a = 100, d::b = "qwerty", c = 900} }).unwrap(),
        t
    );
    ::std::assert_eq!(
        parse(q! { {} }).unwrap_err_string(),
        "missing required field `d::a`, missing required field `d::b`, missing required field `c`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyNamedChildLongPrefixed {
    c: i32,
    #[deluxe(flatten(prefix = d::e))]
    d: MyNamed,
    #[deluxe(flatten(prefix = d::e2))]
    d2: MyNamed,
}

#[test]
fn parse_named_flat_long_prefixed() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyNamedChildLongPrefixed>;

    let t = MyNamedChildLongPrefixed {
        c: 900,
        d: MyNamed {
            a: 100,
            b: "qwerty".into(),
        },
        d2: MyNamed {
            a: 200,
            b: "uiop".into(),
        },
    };
    ::std::assert_eq!(
        parse(
            q! { {d::e::a = 100, d::e::b = "qwerty", d::e2::b = "uiop", d::e2::a = 200, c = 900} }
        )
        .unwrap(),
        t
    );
    ::std::assert_eq!(
        parse(q! { {} }).unwrap_err_string(),
        "missing required field `d::e::a`, missing required field `d::e::b`, \
        missing required field `d::e2::a`, missing required field `d::e2::b`, \
        missing required field `c`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyNamedComplex {
    idents: ::std::vec::Vec<::syn::Ident>,
    #[deluxe(skip)]
    skipped: bool,
    #[deluxe(append)]
    exprs: ::std::vec::Vec<::syn::Expr>,
    #[deluxe(rest)]
    rest: ::std::collections::HashMap<::syn::Path, ::syn::Expr>,
}

#[test]
fn vec_field() {
    use ::std::prelude::v1::*;
    fn cs() -> ::proc_macro2::Span {
        ::proc_macro2::Span::call_site()
    }
    let parse = parse_meta::<MyNamedComplex>;

    ::std::assert_eq!(
        parse(q! { { } }).unwrap_err_string(),
        "missing required field `idents`"
    );
    ::std::assert_eq!(
        parse(q! { { idents } }).unwrap_err_string(),
        "unexpected flag, expected `=` or parentheses"
    );
    ::std::assert_eq!(
        parse(q! { { idents = [] } }).unwrap().idents,
        &[] as &[::syn::Ident]
    );
    ::std::assert_eq!(
        parse(q! { { idents() } }).unwrap().idents,
        &[] as &[::syn::Ident]
    );
    let hello_world = &[
        ::syn::Ident::new("hello", cs()),
        ::syn::Ident::new("world", cs()),
    ];
    ::std::assert_eq!(
        parse(q! { { idents = [hello, world] } }).unwrap().idents,
        hello_world,
    );
    ::std::assert_eq!(
        parse(q! { { idents = [hello, world,] } }).unwrap().idents,
        hello_world,
    );
    ::std::assert_eq!(
        parse(q! { { idents(hello, world) } }).unwrap().idents,
        hello_world,
    );
    ::std::assert_eq!(
        parse(q! { { idents(hello, world,) } }).unwrap().idents,
        hello_world,
    );
    ::std::assert_eq!(
        parse(q! { { idents = (hello, world) } }).unwrap_err_string(),
        "expected square brackets"
    );
    ::std::assert_eq!(
        parse(q! { { idents = [hello world] } }).unwrap_err_string(),
        "expected `,`"
    );
    ::std::assert_eq!(
        parse(q! { { idents = [hello, 123, world] } }).unwrap_err_string(),
        "expected ident"
    );
    ::std::assert_eq!(
        parse(q! { { idents = [hello, 123, world, 456, moon] } }).unwrap_err_string(),
        "expected ident, expected ident"
    );
}

#[test]
fn skipped_field_rest() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyNamedComplex>;
    ::std::assert!(!parse(q! { { idents = [] } }).unwrap().skipped);
    ::std::assert_eq!(
        parse(q! { { idents = [], skipped = true } }).unwrap(),
        MyNamedComplex {
            idents: ::std::vec![],
            skipped: false,
            exprs: ::std::vec![],
            rest: [(
                ::syn::parse_quote! { skipped },
                ::syn::parse_quote! { true },
            )]
            .into_iter()
            .collect(),
        },
    );
}

impl MyNamedComplex {
    #[inline]
    fn exprs_str(&self) -> ::std::string::String {
        use ::quote::ToTokens;
        use ::std::prelude::v1::*;
        self.exprs
            .iter()
            .map(|e| ::std::format!("({})", e.to_token_stream()))
            .collect::<Vec<_>>()
            .join(", ")
    }
    #[inline]
    fn rest_str(&self) -> ::std::string::String {
        use ::quote::ToTokens;
        use ::std::prelude::v1::*;
        let mut rest = self.rest.iter().collect::<Vec<_>>();
        rest.sort_by_key(|(k, _)| k.to_token_stream().to_string());
        rest.into_iter()
            .map(|(k, v)| ::std::format!("({} => {})", k.to_token_stream(), v.to_token_stream()))
            .collect::<Vec<_>>()
            .join(", ")
    }
}

#[test]
fn struct_append() {
    let parse = parse_meta::<MyNamedComplex>;
    ::std::assert_eq!(parse(q! { { idents = [] } }).unwrap().exprs, []);
    ::std::assert_eq!(
        parse(q! { { idents = [], exprs = {} } })
            .unwrap()
            .exprs_str(),
        "({ })",
    );
    ::std::assert_eq!(
        parse(q! { { idents = [], exprs = {}, exprs = 123 + 4 } })
            .unwrap()
            .exprs_str(),
        "({ }), (123 + 4)",
    );
    ::std::assert_eq!(
        parse(q! { { idents = [], exprs = ! } }).unwrap_err_string(),
        "unexpected end of input, expected expression"
    );
}

#[test]
fn struct_rest() {
    let parse = parse_meta::<MyNamedComplex>;
    ::std::assert_eq!(parse(q! { { idents = [] } }).unwrap().exprs, []);
    ::std::assert_eq!(
        parse(q! { { idents = [], abcd = 123 + 4 } })
            .unwrap()
            .rest_str(),
        "(abcd => 123 + 4)",
    );
    ::std::assert_eq!(
        parse(q! { { idents = [], abcd = 123 + 4, hello::world = { "str" } } })
            .unwrap()
            .rest_str(),
        r#"(abcd => 123 + 4), (hello :: world => { "str" })"#,
    );
    ::std::assert_eq!(
        parse(q! { { idents = [], abcd = 123 + 4, hello::world = { "str" }, exprs = 126 - 5 } })
            .unwrap()
            .rest_str(),
        r#"(abcd => 123 + 4), (hello :: world => { "str" })"#,
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyUnnamedRest(i32, #[deluxe(flatten)] ::std::vec::Vec<i32>);

#[test]
fn tuple_struct_rest() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyUnnamedRest>;
    ::std::assert_eq!(
        parse(q! { () }).unwrap_err_string(),
        "missing required field 0"
    );
    ::std::assert_eq!(parse(q! { (1) }).unwrap(), MyUnnamedRest(1, Vec::new()));
    ::std::assert_eq!(
        parse(q! { (1, 2) }).unwrap(),
        MyUnnamedRest(1, ::std::vec![2])
    );
    ::std::assert_eq!(
        parse(q! { (1, 2,) }).unwrap(),
        MyUnnamedRest(1, ::std::vec![2])
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, 3, 4) }).unwrap(),
        MyUnnamedRest(1, ::std::vec![2, 3, 4])
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, 3, 4, "hello", 6) }).unwrap_err_string(),
        "expected integer literal"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
enum MyEmptyEnum {}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyFlatNamed {
    j_a: i32,
    j_b: ::std::string::String,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
enum MyEnum {
    A,
    B(),
    C(i32),
    #[deluxe(transparent)]
    D(bool),
    E(::std::string::String, f64),
    F {},
    #[deluxe(transparent)]
    G {
        pass: ::syn::Path,
    },
    H {
        s: ::std::string::String,
        f: f64,
    },
    #[deluxe(flatten)]
    FlatI {
        i: ::std::string::String,
    },
    #[deluxe(flatten)]
    FlatJ {
        #[deluxe(flatten)]
        named: MyFlatNamed,
    },
    #[deluxe(skip)]
    #[allow(dead_code)]
    K,
}

#[test]
fn parse_enum() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MyEnum>;

    ::std::assert_eq!(
        parse(q! { ( a ) }).unwrap_err_string(),
        "expected curly braces"
    );
    ::std::assert_eq!(parse(q! { { a } }).unwrap(), MyEnum::A);
    ::std::assert_eq!(parse(q! { { a() } }).unwrap(), MyEnum::A);
    ::std::assert_eq!(
        parse(q! { { a(x = 123) } }).unwrap_err_string(),
        "unexpected token `x`"
    );
    ::std::assert_eq!(parse(q! { { b() } }).unwrap(), MyEnum::B());
    ::std::assert_eq!(parse(q! { { b = () } }).unwrap(), MyEnum::B());
    ::std::assert_eq!(
        parse(q! { { b(x = 123) } }).unwrap_err_string(),
        "unexpected token `x`"
    );
    ::std::assert_eq!(parse(q! { { c(123) } }).unwrap(), MyEnum::C(123));
    ::std::assert_eq!(
        parse(q! { { c } }).unwrap_err_string(),
        "unexpected flag, expected `=` or parentheses"
    );
    ::std::assert_eq!(
        parse(q! { { c = 123 } }).unwrap_err_string(),
        "expected parentheses"
    );
    ::std::assert_eq!(parse(q! { { d(true) } }).unwrap(), MyEnum::D(true));
    ::std::assert_eq!(parse(q! { { d = true } }).unwrap(), MyEnum::D(true));
    ::std::assert_eq!(parse(q! { { d } }).unwrap(), MyEnum::D(true));
    ::std::assert_eq!(
        parse(q! { { e("hello", 4.0) } }).unwrap(),
        MyEnum::E("hello".into(), 4.0),
    );
    ::std::assert_eq!(parse(q! { { f } }).unwrap(), MyEnum::F {});
    ::std::assert_eq!(parse(q! { { f() } }).unwrap(), MyEnum::F {});
    ::std::assert_eq!(parse(q! { { f = {} } }).unwrap(), MyEnum::F {});
    ::std::assert_eq!(
        parse(q! { { g(themod::theitem) } }).unwrap(),
        MyEnum::G {
            pass: ::syn::parse_quote! { themod::theitem }
        }
    );
    ::std::assert_eq!(
        parse(q! { { g = themod::theitem } }).unwrap(),
        MyEnum::G {
            pass: ::syn::parse_quote! { themod::theitem }
        }
    );
    ::std::assert_eq!(
        parse(q! { { h(s = "qwerty", f = 1.0) } }).unwrap(),
        MyEnum::H {
            s: "qwerty".into(),
            f: 1.0
        }
    );
    ::std::assert_eq!(
        parse(q! { { j_a = 123, j_b = "asdf" } }).unwrap(),
        MyEnum::FlatJ {
            named: MyFlatNamed {
                j_a: 123,
                j_b: "asdf".into(),
            }
        },
    );
    ::std::assert_eq!(
        parse(q! { { i = "asdf" } }).unwrap(),
        MyEnum::FlatI { i: "asdf".into() }
    );
    ::std::assert_eq!(
        parse(q! { { x() } }).unwrap_err_string(),
        "unknown field `x`, expected one of `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, fields from `FlatJ`",
    );
    ::std::assert_eq!(
        parse(q! { { k } }).unwrap_err_string(),
        "unknown field `k`, expected one of `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, fields from `FlatJ`",
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
enum MySimpleEnum {
    A,
    B,
    C,
}

#[test]
fn parse_simple_enum() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<MySimpleEnum>;

    ::std::assert_eq!(parse(q! { { a } }).unwrap(), MySimpleEnum::A);
    ::std::assert_eq!(parse(q! { { b } }).unwrap(), MySimpleEnum::B);
    ::std::assert_eq!(parse(q! { { c } }).unwrap(), MySimpleEnum::C);
    ::std::assert_eq!(
        parse(q! { { a, b } }).unwrap_err_string(),
        "expected only one enum variant, got `a` and `b`"
    );
    ::std::assert_eq!(
        parse(q! { { a, c } }).unwrap_err_string(),
        "expected only one enum variant, got `a` and `c`"
    );
    ::std::assert_eq!(
        parse(q! { { d } }).unwrap_err_string(),
        "unknown field `d`, expected one of `a`, `b`, `c`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct StructWith {
    normal: ::std::string::String,
    #[deluxe(with = ::deluxe::with::from_str)]
    str_int: i32,
}

::deluxe::define_with_optional!(
    pub mod custom_int_option,
    ::deluxe::with::from_str,
    i32,
);
::deluxe::define_with_collection!(
    pub mod custom_int_vec,
    ::deluxe::with::from_str,
    ::std::vec::Vec<i32>,
);

::deluxe::define_with_map!(
    pub mod custom_int_map,
    ::deluxe::with::mod_path,
    ::deluxe::with::from_str,
    ::std::collections::HashMap<::syn::Path, i32>,
);

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
#[deluxe(transparent(flatten_unnamed, append))]
struct StructWithTransparent {
    #[deluxe(with = custom_int_vec)]
    int_vec: ::std::vec::Vec<i32>,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct StructWithExtended {
    #[deluxe(with = custom_int_option)]
    int: ::std::option::Option<i32>,
    #[deluxe(with = custom_int_vec)]
    int_vec: ::std::vec::Vec<i32>,
    #[deluxe(append, rename = int_append, with = custom_int_vec)]
    int_vec2: ::std::vec::Vec<i32>,
    #[deluxe(append, default)]
    int_vec3: StructWithTransparent,
    #[deluxe(rest, with = custom_int_map)]
    int_map: ::std::collections::HashMap<::syn::Path, i32>,
}

#[test]
fn parse_with() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<StructWith>;

    ::std::assert_eq!(
        parse(q! { { normal = "abc", str_int = "123" } }).unwrap(),
        StructWith {
            normal: "abc".into(),
            str_int: 123
        }
    );
    ::std::assert_eq!(
        parse(q! { { normal = "abc", str_int = 123 } }).unwrap_err_string(),
        "expected string literal"
    );

    let make_path = |s| ::syn::parse_str::<::syn::Path>(s).unwrap();
    let parse = parse_meta::<StructWithExtended>;
    ::std::assert_eq!(
        parse(q! { { int = -4, int_vec = ["1", "2"] } }).unwrap_err_string(),
        "expected string literal"
    );
    ::std::assert_eq!(
        parse(q! { { int_vec = [1] } }).unwrap_err_string(),
        "expected string literal"
    );
    ::std::assert_eq!(
        parse(q! { { int = "-4", int_vec = ["1", "2"] } }).unwrap(),
        StructWithExtended {
            int: Some(-4),
            int_vec: ::std::vec![1, 2],
            int_vec2: ::std::vec![],
            int_vec3: Default::default(),
            int_map: [].into()
        }
    );
    ::std::assert_eq!(
        parse(q! { { int_vec = [], int_append = "1", int_append = "2" } }).unwrap(),
        StructWithExtended {
            int: None,
            int_vec: ::std::vec![],
            int_vec2: ::std::vec![1, 2],
            int_vec3: Default::default(),
            int_map: [].into()
        }
    );
    ::std::assert_eq!(
        parse(q! { { int_vec = [], int_append = "1", unknown = "2", hello = "3" } }).unwrap(),
        StructWithExtended {
            int: None,
            int_vec: ::std::vec![],
            int_vec2: ::std::vec![1],
            int_vec3: Default::default(),
            int_map: [(make_path("unknown"), 2), (make_path("hello"), 3)].into()
        }
    );
    ::std::assert_eq!(
        parse(q! { { int_vec = [], int_vec3 = "1", int_vec3 = "2" } }).unwrap(),
        StructWithExtended {
            int: None,
            int_vec: ::std::vec![],
            int_vec2: ::std::vec![],
            int_vec3: StructWithTransparent {
                int_vec: ::std::vec![1, 2],
            },
            int_map: [].into()
        }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct StructNames {
    #[deluxe(rename = sixty_four, default)]
    renamed: u64,
    #[deluxe(alias = thirty_two, default)]
    aliased: u32,
    #[deluxe(alias = another, alias = another2, default)]
    many_aliases: u32,
    #[deluxe(rename = sixteen, alias = another_sixteen, alias = another2_sixteen, default)]
    alias_renamed: u16,
}

#[test]
fn struct_field_names() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<StructNames>;

    ::std::assert_eq!(parse(q! { { sixty_four = 64 } }).unwrap().renamed, 64);
    ::std::assert_eq!(
        parse(q! { { renamed = 64 } }).unwrap_err_string(),
        "unknown field `renamed`"
    );
    ::std::assert_eq!(
        parse(q! { { sixty_four = 64, sixty_four = 65 } }).unwrap_err_string(),
        "duplicate attribute for `sixty_four`"
    );
    ::std::assert_eq!(
        parse(q! { { sixty_four = 64, renamed = 65 } }).unwrap_err_string(),
        "unknown field `renamed`"
    );

    ::std::assert_eq!(parse(q! { { aliased = 32 } }).unwrap().aliased, 32);
    ::std::assert_eq!(parse(q! { { thirty_two = 32 } }).unwrap().aliased, 32);
    ::std::assert_eq!(
        parse(q! { { aliased = 32, thirty_two = 33 } }).unwrap_err_string(),
        "duplicate attribute for `aliased`"
    );

    ::std::assert_eq!(
        parse(q! { { many_aliases = 32 } }).unwrap().many_aliases,
        32
    );
    ::std::assert_eq!(parse(q! { { another = 32 } }).unwrap().many_aliases, 32);
    ::std::assert_eq!(parse(q! { { another2 = 32 } }).unwrap().many_aliases, 32);
    ::std::assert_eq!(
        parse(q! { { many_aliases = 32, another = 33, another2 = 34 } }).unwrap_err_string(),
        "duplicate attribute for `many_aliases`, duplicate attribute for `many_aliases`"
    );

    ::std::assert_eq!(parse(q! { { sixteen = 16 } }).unwrap().alias_renamed, 16);
    ::std::assert_eq!(
        parse(q! { { another_sixteen = 16 } })
            .unwrap()
            .alias_renamed,
        16
    );
    ::std::assert_eq!(
        parse(q! { { another2_sixteen = 16 } })
            .unwrap()
            .alias_renamed,
        16
    );
    ::std::assert_eq!(
        parse(q! { { alias_renamed = 16 } }).unwrap_err_string(),
        "unknown field `alias_renamed`, did you mean `aliased`?"
    );

    ::std::assert_eq!(
        <StructNames as ::deluxe::ParseMetaFlatNamed>::field_names(),
        &[
            "sixty_four",
            "aliased",
            "thirty_two",
            "many_aliases",
            "another",
            "another2",
            "sixteen",
            "another_sixteen",
            "another2_sixteen"
        ]
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
enum EnumNames {
    #[deluxe(rename = renamed_a)]
    A,
    #[deluxe(alias = alias_b)]
    B,
    #[deluxe(alias = another_c, alias = another2_c)]
    C,
    #[deluxe(rename = renamed_d, alias = another_d, alias = another2_d)]
    D,
}

#[test]
fn enum_field_names() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<EnumNames>;

    ::std::assert_eq!(parse(q! { { renamed_a } }).unwrap(), EnumNames::A);
    ::std::assert_eq!(parse(q! { { b } }).unwrap(), EnumNames::B);
    ::std::assert_eq!(parse(q! { { alias_b } }).unwrap(), EnumNames::B);
    ::std::assert_eq!(parse(q! { { c } }).unwrap(), EnumNames::C);
    ::std::assert_eq!(parse(q! { { another_c } }).unwrap(), EnumNames::C);
    ::std::assert_eq!(parse(q! { { another2_c } }).unwrap(), EnumNames::C);
    ::std::assert_eq!(parse(q! { { renamed_d } }).unwrap(), EnumNames::D);
    ::std::assert_eq!(parse(q! { { another_d } }).unwrap(), EnumNames::D);
    ::std::assert_eq!(parse(q! { { another2_d } }).unwrap(), EnumNames::D);
    ::std::assert_eq!(
        parse(q! { { a } }).unwrap_err_string(),
        "unknown field `a`, expected one of `renamed_a`, `b`, `c`, `renamed_d`"
    );
    ::std::assert_eq!(
        parse(q! { { d } }).unwrap_err_string(),
        "unknown field `d`, expected one of `renamed_a`, `b`, `c`, `renamed_d`"
    );

    ::std::assert_eq!(
        <EnumNames as ::deluxe::ParseMetaFlatNamed>::field_names(),
        &[
            "renamed_a",
            "b",
            "alias_b",
            "c",
            "another_c",
            "another2_c",
            "renamed_d",
            "another_d",
            "another2_d",
        ]
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
#[deluxe(default)]
struct StructDefault {
    value0: i32,
    #[deluxe(default = 1)]
    value1: i32,
}

#[test]
fn struct_defaults() {
    use ::std::prelude::v1::*;

    let parse = parse_meta::<StructDefault>;
    ::std::assert_eq!(
        parse(q! { { } }).unwrap(),
        StructDefault {
            value0: 0,
            value1: 1
        }
    );
    ::std::assert_eq!(
        parse(q! { { value0 = -1, value1 = 2 } }).unwrap(),
        StructDefault {
            value0: -1,
            value1: 2
        }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(default = Self { value1: 1, value2: 2 })]
struct StructDefaultExpr {
    value1: i32,
    value2: i32,
}

#[test]
fn struct_default_expr() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<StructDefaultExpr>;
    ::std::assert_eq!(
        parse(q! { { } }).unwrap(),
        StructDefaultExpr {
            value1: 1,
            value2: 2
        }
    );
    ::std::assert_eq!(
        parse(q! { { value1 = 11 } }).unwrap(),
        StructDefaultExpr {
            value1: 11,
            value2: 2
        }
    );
    ::std::assert_eq!(
        parse(q! { { value2 = 22 } }).unwrap(),
        StructDefaultExpr {
            value1: 1,
            value2: 22
        }
    );
    ::std::assert_eq!(
        parse(q! { { value1 = 11, value2 = 22 } }).unwrap(),
        StructDefaultExpr {
            value1: 11,
            value2: 22
        }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
struct StructDefaultTuple(i32, #[deluxe(default)] i32);

#[test]
fn struct_default_tuple() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<StructDefaultTuple>;
    ::std::assert_eq!(
        parse(q! {}).unwrap_err_string(),
        "unexpected end of input, expected parentheses"
    );
    ::std::assert_eq!(
        parse(q! { () }).unwrap_err_string(),
        "missing required field 0"
    );
    ::std::assert_eq!(parse(q! { (1) }).unwrap(), StructDefaultTuple(1, 0));
    ::std::assert_eq!(parse(q! { (1, 2) }).unwrap(), StructDefaultTuple(1, 2));
    ::std::assert_eq!(
        parse(q! { (1, 2, 3) }).unwrap_err_string(),
        "unexpected token `3`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(default = Self(1, 2))]
struct StructDefaultTupleExpr(i32, i32);

#[test]
fn struct_default_tuple_expr() {
    use ::std::prelude::v1::*;

    let parse = parse_meta::<StructDefaultTupleExpr>;
    ::std::assert_eq!(parse(q! { () }).unwrap(), StructDefaultTupleExpr(1, 2));
    ::std::assert_eq!(parse(q! { (3) }).unwrap(), StructDefaultTupleExpr(3, 2));
    ::std::assert_eq!(parse(q! { (3,) }).unwrap(), StructDefaultTupleExpr(3, 2));
    ::std::assert_eq!(parse(q! { (3, 4) }).unwrap(), StructDefaultTupleExpr(3, 4));
    ::std::assert_eq!(parse(q! { (3, 4,) }).unwrap(), StructDefaultTupleExpr(3, 4));
    ::std::assert_eq!(
        parse(q! { (3, 4,,) }).unwrap_err_string(),
        "unexpected token `,`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct FieldDefaults {
    #[deluxe(default = MyNewtype(::std::string::String::new()))]
    name: MyNewtype,
    #[deluxe(default)]
    value0: i32,
    #[deluxe(default = 1)]
    value1: i32,
    value: i32,
}

#[test]
fn field_defaults() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<FieldDefaults>;
    ::std::assert_eq!(
        parse(q! { { } }).unwrap_err_string(),
        "missing required field `value`"
    );
    ::std::assert_eq!(
        parse(q! { { value = 123 } }).unwrap(),
        FieldDefaults {
            name: MyNewtype(String::from("")),
            value0: 0,
            value1: 1,
            value: 123,
        }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
#[deluxe(default)]
enum EnumDefault {
    #[default]
    A,
    B,
    C(#[deluxe(default)] i32),
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(default = Self::A)]
enum EnumDefaultExpr {
    A,
    B,
    C,
}

#[test]
fn enum_defaults() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<EnumDefault>;
    ::std::assert_eq!(parse(q! { { } }).unwrap(), EnumDefault::A);
    ::std::assert_eq!(parse(q! { { c } }).unwrap(), EnumDefault::C(0));
    ::std::assert_eq!(parse(q! { { c() } }).unwrap(), EnumDefault::C(0));
    ::std::assert_eq!(parse(q! { { c = () } }).unwrap(), EnumDefault::C(0));
    ::std::assert_eq!(parse(q! { { c(1) } }).unwrap(), EnumDefault::C(1));
    ::std::assert_eq!(parse(q! { { c(1,) } }).unwrap(), EnumDefault::C(1));
    ::std::assert_eq!(
        parse(q! { { c = (,) } }).unwrap_err_string(),
        "expected integer literal"
    );

    let parse = parse_meta::<EnumDefaultExpr>;
    ::std::assert_eq!(parse(q! { { } }).unwrap(), EnumDefaultExpr::A);
}

use ::deluxe as renamed_deluxe;

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(crate = renamed_deluxe)]
struct RenamedCrate(i32);

#[test]
fn renamed_crate() {
    let parse = parse_meta::<RenamedCrate>;
    ::std::assert_eq!(parse(q! { (50) }).unwrap(), RenamedCrate(50));
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(allow_unknown_fields)]
struct StructAllowUnknown {
    value: i32,
}

#[test]
fn struct_allow_unknown() {
    let parse = parse_meta::<StructAllowUnknown>;
    ::std::assert_eq!(
        parse(q! { { value = 10 } }).unwrap(),
        StructAllowUnknown { value: 10 }
    );
    ::std::assert_eq!(
        parse(q! { { value = 10, another = "hello" } }).unwrap(),
        StructAllowUnknown { value: 10 }
    );
    ::std::assert_eq!(
        parse(
            q! { { value = 10, complex = ::c::X + 123 + (Z(Y) % { x[0].a }), another = "hello" } }
        )
        .unwrap(),
        StructAllowUnknown { value: 10 }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
enum EnumAllow {
    Known {
        value: i32,
    },
    #[deluxe(allow_unknown_fields)]
    Unknown {
        value: i32,
    },
    FlattenedKnown {
        #[deluxe(flatten)]
        s: MyNamed,
    },
    FlattenedUnknown {
        #[deluxe(flatten)]
        s: StructAllowUnknown,
    },
}

#[test]
fn enum_allow_unknown() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<EnumAllow>;
    ::std::assert_eq!(
        parse(q! { { known(value(50)) } }).unwrap(),
        EnumAllow::Known { value: 50 }
    );
    ::std::assert_eq!(
        parse(q! { { known(value(50)), unknown(value(51)) } }).unwrap_err_string(),
        "expected only one enum variant, got `known` and `unknown`"
    );
    ::std::assert_eq!(
        parse(q! { { known(value(50), another("thing")) } }).unwrap_err_string(),
        "unknown field `another`"
    );
    ::std::assert_eq!(
        parse(q! { { known(value(50), another("thing")), unknown(value("50")) } }).unwrap_err_string(),
        "unknown field `another`, expected only one enum variant, got `known` and `unknown`, expected integer literal"
    );
    ::std::assert_eq!(
        parse(q! { { unknown(value(50)) } }).unwrap(),
        EnumAllow::Unknown { value: 50 }
    );
    ::std::assert_eq!(
        parse(q! { { unknown(value(50), another("thing")) } }).unwrap(),
        EnumAllow::Unknown { value: 50 }
    );
    ::std::assert_eq!(
        parse(q! { { flattened_known(a(50), b("thing")) } }).unwrap(),
        EnumAllow::FlattenedKnown {
            s: MyNamed {
                a: 50,
                b: String::from("thing")
            }
        }
    );
    ::std::assert_eq!(
        parse(q! { { flattened_known(a(50), b("thing"), another("two")) } }).unwrap_err_string(),
        "unknown field `another`"
    );
    ::std::assert_eq!(
        parse(q! { { flattened_unknown(value(60)) } }).unwrap(),
        EnumAllow::FlattenedUnknown {
            s: StructAllowUnknown { value: 60 }
        }
    );
    ::std::assert_eq!(
        parse(q! { { flattened_unknown(value(60), another("thing")) } }).unwrap(),
        EnumAllow::FlattenedUnknown {
            s: StructAllowUnknown { value: 60 }
        }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent(flatten_named))]
struct MyTransparentUnnamedStruct(MyNamed);

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent(flatten_named))]
struct MyTransparentNamedStruct {
    named: MyNamed,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent(flatten_unnamed, append))]
struct MyTransparentUnnamedVec(::std::vec::Vec<i32>);

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent(flatten_unnamed, append))]
struct MyTransparentNamedVec {
    nums: ::std::vec::Vec<i32>,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent(rest))]
struct MyTransparentUnnamedMap(::std::collections::HashMap<::syn::Path, i32>);

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(transparent(rest))]
struct MyTransparentNamedMap {
    nums: ::std::collections::HashMap<::syn::Path, i32>,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
enum TransparentHolder {
    A {
        #[deluxe(flatten)]
        s: MyTransparentUnnamedStruct,
    },
    B {
        #[deluxe(flatten)]
        s: MyTransparentNamedStruct,
    },
    C(#[deluxe(flatten)] MyTransparentUnnamedVec),
    D(#[deluxe(flatten)] MyTransparentNamedVec),
    E {
        #[deluxe(append)]
        v: MyTransparentUnnamedVec,
    },
    F {
        #[deluxe(append)]
        v: MyTransparentNamedVec,
    },
    G {
        #[deluxe(rest)]
        r: MyTransparentUnnamedMap,
    },
    H {
        #[deluxe(rest)]
        r: MyTransparentNamedMap,
    },
}

#[test]
fn transparent_flat() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<TransparentHolder>;
    ::std::assert_eq!(
        parse(q! { { a(a(4), b("hello")) } }).unwrap(),
        TransparentHolder::A {
            s: MyTransparentUnnamedStruct(MyNamed {
                a: 4,
                b: String::from("hello")
            })
        }
    );
    ::std::assert_eq!(
        parse(q! { { b(a(4), b("hello")) } }).unwrap(),
        TransparentHolder::B {
            s: MyTransparentNamedStruct {
                named: MyNamed {
                    a: 4,
                    b: String::from("hello")
                }
            }
        }
    );
    ::std::assert_eq!(
        parse(q! { { c } }).unwrap(),
        TransparentHolder::C(MyTransparentUnnamedVec(::std::vec![]))
    );
    ::std::assert_eq!(
        parse(q! { { c() } }).unwrap(),
        TransparentHolder::C(MyTransparentUnnamedVec(::std::vec![]))
    );
    ::std::assert_eq!(
        parse(q! { { c(1, 2, 3) } }).unwrap(),
        TransparentHolder::C(MyTransparentUnnamedVec(::std::vec![1, 2, 3]))
    );
    ::std::assert_eq!(
        parse(q! { { d } }).unwrap(),
        TransparentHolder::D(MyTransparentNamedVec {
            nums: ::std::vec![]
        })
    );
    ::std::assert_eq!(
        parse(q! { { d() } }).unwrap(),
        TransparentHolder::D(MyTransparentNamedVec {
            nums: ::std::vec![]
        })
    );
    ::std::assert_eq!(
        parse(q! { { d(1, 2, 3) } }).unwrap(),
        TransparentHolder::D(MyTransparentNamedVec {
            nums: ::std::vec![1, 2, 3]
        })
    );
    ::std::assert_eq!(
        parse(q! { { e(v(1), v(2), v(3)) } }).unwrap(),
        TransparentHolder::E {
            v: MyTransparentUnnamedVec(::std::vec![1, 2, 3])
        }
    );
    ::std::assert_eq!(
        parse(q! { { f(v(1), v(2), v(3)) } }).unwrap(),
        TransparentHolder::F {
            v: MyTransparentNamedVec {
                nums: ::std::vec![1, 2, 3]
            }
        }
    );

    let map = [("a", 1), ("b", 2), ("c", 3)]
        .into_iter()
        .map(|(k, v)| {
            let k = ::syn::Ident::new(k, ::proc_macro2::Span::call_site());
            let k: ::syn::Path = ::syn::parse_quote! { #k };
            (k, v)
        })
        .collect::<::std::collections::HashMap<_, _>>();

    ::std::assert_eq!(
        parse(q! { { g(a(1), b(2), c(3)) } }).unwrap(),
        TransparentHolder::G {
            r: MyTransparentUnnamedMap(map.clone())
        }
    );
    ::std::assert_eq!(
        parse(q! { { h(a(1), b(2), c(3)) } }).unwrap(),
        TransparentHolder::H {
            r: MyTransparentNamedMap { nums: map }
        }
    );
}

#[derive(PartialEq, Debug)]
struct CustomAppendSum(i32);

impl ::deluxe::ParseMetaAppend for CustomAppendSum {
    fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> ::deluxe::Result<Self>
    where
        S: ::std::borrow::Borrow<renamed_deluxe::____private::ParseBuffer<'s>>,
        I: ::std::iter::IntoIterator<Item = P>,
        I::IntoIter: ::std::clone::Clone,
        P: ::std::convert::AsRef<str>,
    {
        use ::std::prelude::v1::*;
        let mut value = 0;
        let errors = ::deluxe::Errors::new();
        let paths = paths.into_iter();
        ::deluxe_core::parse_helpers::parse_struct(inputs, |input, p, pspan| {
            if paths.clone().any(|path| path.as_ref() == p) {
                value += ::deluxe_core::parse_helpers::parse_named_meta_item::<i32>(input, pspan)?;
            } else {
                ::deluxe_core::parse_helpers::skip_meta_item(input);
            }
            ::deluxe::Result::Ok(())
        })?;
        errors.check()?;
        ::deluxe::Result::Ok(Self(value))
    }
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct CustomAppend {
    first: i32,
    #[deluxe(append)]
    sum: CustomAppendSum,
}

#[test]
fn custom_append_sum() {
    let parse = parse_meta::<CustomAppend>;
    ::std::assert_eq!(
        parse(q! { { first = 50, sum = 2, sum = 3 } }).unwrap(),
        CustomAppend {
            first: 50,
            sum: CustomAppendSum(5)
        }
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct MyOptionalNamed {
    #[deluxe(default)]
    a: i32,
    #[deluxe(default)]
    b: ::std::string::String,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct PositionalAndNamed(
    #[deluxe(default)] i32,
    #[deluxe(default)] i32,
    #[deluxe(flatten)] MyOptionalNamed,
);

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct NestedPositionalAndNamed(
    i32,
    #[deluxe(flatten)] MyUnnamed,
    #[deluxe(default)] i32,
    #[deluxe(flatten)] PositionalAndNamed,
);

#[test]
fn positional_and_named() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<PositionalAndNamed>;

    ::std::assert_eq!(
        parse(q! { (1) }).unwrap(),
        PositionalAndNamed(1, 0, MyOptionalNamed { a: 0, b: "".into() })
    );
    ::std::assert_eq!(
        parse(q! { (1, 2) }).unwrap(),
        PositionalAndNamed(1, 2, MyOptionalNamed { a: 0, b: "".into() })
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, b = "4" ) }).unwrap(),
        PositionalAndNamed(
            1,
            2,
            MyOptionalNamed {
                a: 0,
                b: "4".into()
            }
        )
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, a = 3, b = "4" ) }).unwrap(),
        PositionalAndNamed(
            1,
            2,
            MyOptionalNamed {
                a: 3,
                b: "4".into()
            }
        )
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, b = "4", a = 3 ) }).unwrap(),
        PositionalAndNamed(
            1,
            2,
            MyOptionalNamed {
                a: 3,
                b: "4".into()
            }
        )
    );

    let parse = parse_meta::<NestedPositionalAndNamed>;

    ::std::assert_eq!(
        parse(q! { (1, 2, "3") }).unwrap(),
        NestedPositionalAndNamed(
            1,
            MyUnnamed(2, "3".into()),
            0,
            PositionalAndNamed(0, 0, MyOptionalNamed { a: 0, b: "".into() })
        )
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, "3", 4, 5) }).unwrap(),
        NestedPositionalAndNamed(
            1,
            MyUnnamed(2, "3".into()),
            4,
            PositionalAndNamed(5, 0, MyOptionalNamed { a: 0, b: "".into() })
        )
    );
    ::std::assert_eq!(
        parse(q! { (1, 2, "3", 4, 5, 6, a = 7, b = "8" ) }).unwrap(),
        NestedPositionalAndNamed(
            1,
            MyUnnamed(2, "3".into()),
            4,
            PositionalAndNamed(
                5,
                6,
                MyOptionalNamed {
                    a: 7,
                    b: "8".into()
                }
            )
        )
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
enum KwEnum {
    #[default]
    A,
    B,
    Const,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct FlattenedEnum {
    #[deluxe(flatten)]
    kw: KwEnum,
}

#[test]
fn flattened_enum() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<FlattenedEnum>;

    ::std::assert_eq!(
        parse(q! { { a } }).unwrap(),
        FlattenedEnum { kw: KwEnum::A }
    );
    ::std::assert_eq!(
        parse(q! { { b } }).unwrap(),
        FlattenedEnum { kw: KwEnum::B }
    );
    ::std::assert_eq!(
        parse(q! { { const } }).unwrap(),
        FlattenedEnum { kw: KwEnum::Const }
    );
    ::std::assert_eq!(
        parse(q! { {} }).unwrap_err_string(),
        "expected one of `a`, `b`, `const`"
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct FlagStruct {
    myflag: ::deluxe::Flag,
    #[deluxe(default)]
    value: i32,
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
// should always error when encountering the field
struct FlagTupleStruct(::deluxe::Flag);

#[test]
fn flag() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<FlagStruct>;

    ::std::assert_eq!(
        parse(q! { { myflag } }).unwrap(),
        FlagStruct {
            myflag: true.into(),
            value: 0,
        }
    );
    ::std::assert_eq!(
        parse(q! { {} }).unwrap(),
        FlagStruct {
            myflag: false.into(),
            value: 0,
        }
    );
    ::std::assert_eq!(
        parse(q! { { myflag, value = 123 } }).unwrap(),
        FlagStruct {
            myflag: true.into(),
            value: 123,
        }
    );
    ::std::assert_eq!(
        parse(q! { { myflag = true } }).unwrap_err_string(),
        "unexpected token",
    );
    ::std::assert_eq!(
        parse(q! { { myflag(true) } }).unwrap_err_string(),
        "unexpected token",
    );

    let parse = parse_meta::<FlagTupleStruct>;

    ::std::assert_eq!(
        parse(q! { (myflag) }).unwrap_err_string(),
        "field with type `Flag` can only be a named field with no value",
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(and_then = Self::validate_min, and_then = Self::validate_max)]
struct AndThens {
    a: ::deluxe::SpannedValue<i32>,
    b: i32,
}

impl AndThens {
    fn validate_min(self) -> ::deluxe::Result<Self> {
        if *self.a + self.b <= -10 {
            ::deluxe::Result::Err(::deluxe::Error::new(
                ::syn::spanned::Spanned::span(&self.a),
                "sum of a and b must be above -10",
            ))
        } else {
            ::deluxe::Result::Ok(self)
        }
    }
    fn validate_max(self) -> ::deluxe::Result<Self> {
        if *self.a + self.b >= 10 {
            ::deluxe::Result::Err(::deluxe::Error::new(
                ::syn::spanned::Spanned::span(&self.a),
                "sum of a and b must be below 10",
            ))
        } else {
            ::deluxe::Result::Ok(self)
        }
    }
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
#[deluxe(and_then = Self::validate_min, and_then = Self::validate_max)]
enum AndThensEnum {
    Values {
        a: ::deluxe::SpannedValue<i32>,
        b: i32,
    },
    Empty,
}

impl AndThensEnum {
    fn validate_min(self) -> ::deluxe::Result<Self> {
        if let Self::Values { a, b } = &self {
            if **a + *b <= -10 {
                return ::deluxe::Result::Err(::deluxe::Error::new(
                    ::syn::spanned::Spanned::span(a),
                    "sum of a and b must be above -10",
                ));
            }
        }
        ::deluxe::Result::Ok(self)
    }
    fn validate_max(self) -> ::deluxe::Result<Self> {
        if let Self::Values { a, b } = &self {
            if **a + *b >= 10 {
                return ::deluxe::Result::Err(::deluxe::Error::new(
                    ::syn::spanned::Spanned::span(a),
                    "sum of a and b must be below 10",
                ));
            }
        }
        ::deluxe::Result::Ok(self)
    }
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
#[deluxe(and_then = Self::validate)]
struct OnlyOne {
    a: ::std::option::Option<::std::string::String>,
    b: ::std::option::Option<::std::string::String>,
}

impl OnlyOne {
    fn validate(self) -> ::deluxe::Result<Self> {
        let errors = ::deluxe::Errors::new();
        let Self { a, b } = &self;
        ::deluxe::validations::only_one!("", &errors, a, b);
        errors.into_result(self)
    }
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
    Default,
)]
#[deluxe(and_then = Self::validate)]
struct AllOrNone {
    a: ::std::option::Option<::std::string::String>,
    b: ::std::option::Option<::std::string::String>,
}

impl AllOrNone {
    fn validate(self) -> ::deluxe::Result<Self> {
        let errors = ::deluxe::Errors::new();
        let Self { a, b } = &self;
        ::deluxe::validations::all_or_none!("", &errors, a, b);
        errors.into_result(self)
    }
}

#[test]
fn and_then() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<AndThens>;

    ::std::assert_eq!(
        parse(q! { { a = 5, b = 4 } }).unwrap(),
        AndThens { a: 5.into(), b: 4 }
    );
    ::std::assert_eq!(
        parse(q! { { a = -5, b = -6 } }).unwrap_err_string(),
        "sum of a and b must be above -10",
    );
    ::std::assert_eq!(
        parse(q! { { a = 5, b = 6 } }).unwrap_err_string(),
        "sum of a and b must be below 10",
    );

    let parse = parse_meta::<AndThensEnum>;

    ::std::assert_eq!(parse(q! { { empty } }).unwrap(), AndThensEnum::Empty);
    ::std::assert_eq!(
        parse(q! { { values(a = 5, b = 4) } }).unwrap(),
        AndThensEnum::Values { a: 5.into(), b: 4 }
    );
    ::std::assert_eq!(
        parse(q! { { values(a = -5, b = -6) } }).unwrap_err_string(),
        "sum of a and b must be above -10",
    );
    ::std::assert_eq!(
        parse(q! { { values(a = 5, b = 6) } }).unwrap_err_string(),
        "sum of a and b must be below 10",
    );

    let parse = parse_meta::<OnlyOne>;
    ::std::assert_eq!(parse(q! { {} }).unwrap(), OnlyOne::default());
    ::std::assert_eq!(
        parse(q! { {a("a")} }).unwrap(),
        OnlyOne {
            a: Some("a".into()),
            b: None
        }
    );
    ::std::assert_eq!(
        parse(q! { {b("b")} }).unwrap(),
        OnlyOne {
            a: None,
            b: Some("b".into()),
        }
    );
    // error appears twice, once on each attribute
    ::std::assert_eq!(
        parse(q! { {a("a"), b("b")} }).unwrap_err_string(),
        "only one of `a`, `b` is allowed, only one of `a`, `b` is allowed",
    );

    let parse = parse_meta::<AllOrNone>;
    ::std::assert_eq!(parse(q! { {} }).unwrap(), AllOrNone::default());
    ::std::assert_eq!(
        parse(q! { {a("a"), b("b")} }).unwrap(),
        AllOrNone {
            a: Some("a".into()),
            b: Some("b".into()),
        }
    );
    ::std::assert_eq!(
        parse(q! { {a("a")} }).unwrap_err_string(),
        "`b` must also be set in order to use `a`",
    );
    ::std::assert_eq!(
        parse(q! { {b("b")} }).unwrap_err_string(),
        "`a` must also be set in order to use `b`",
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct FieldTransforms {
    #[deluxe(map = |x: ::syn::Ident| ::std::string::ToString::to_string(&x))]
    ident: ::std::string::String,
    #[deluxe(map = |x: ::syn::Ident| ::std::string::ToString::to_string(&x))]
    #[deluxe(map = |s| ::std::format!("prefix_{s}"))]
    prefixed_ident: ::std::string::String,
    #[deluxe(and_then = |u: u32| <u16 as ::std::convert::TryFrom<_>>::try_from(u)
            .map_err(|_| ::syn::Error::new(::proc_macro2::Span::call_site(), "my_int too big")))]
    my_int: u16,
    #[deluxe(and_then = |u: u32| <u16 as ::std::convert::TryFrom<_>>::try_from(u)
            .map_err(|_| ::syn::Error::new(::proc_macro2::Span::call_site(), "is_one too big")))]
    #[deluxe(map = |u| u == 1)]
    is_one: bool,
}

#[test]
fn field_transforms() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<FieldTransforms>;

    ::std::assert_eq!(
        parse(q! { { ident = hello, prefixed_ident = world, my_int = 200, is_one = 1, } }).unwrap(),
        FieldTransforms {
            ident: String::from("hello"),
            prefixed_ident: String::from("prefix_world"),
            my_int: 200,
            is_one: true
        }
    );
    ::std::assert_eq!(
        parse(q! { { ident = goodbye, prefixed_ident = moon, my_int = 300, is_one = 123, } })
            .unwrap(),
        FieldTransforms {
            ident: String::from("goodbye"),
            prefixed_ident: String::from("prefix_moon"),
            my_int: 300,
            is_one: false
        }
    );
    ::std::assert_eq!(
        parse(q! { { ident = hello, prefixed_ident = world, my_int = 100000, is_one = 1, } })
            .unwrap_err_string(),
        "my_int too big",
    );
    ::std::assert_eq!(
        parse(q! { { ident = hello, prefixed_ident = world, my_int = 200000, is_one = 100000, } })
            .unwrap_err_string(),
        "my_int too big, is_one too big",
    );
}

#[derive(
    ::deluxe::ParseAttributes,
    ::deluxe::ExtractAttributes,
    ::deluxe::ParseMetaItem,
    PartialEq,
    Debug,
)]
struct RawIdentKeys {
    r#struct: ::syn::Type,
    r#trait: ::syn::Type,
}

#[test]
fn raw_ident_keys() {
    use ::std::prelude::v1::*;
    let parse = parse_meta::<RawIdentKeys>;

    ::std::assert_eq!(
        parse(q! { { struct = A, trait = B } }).unwrap(),
        RawIdentKeys {
            r#struct: ::syn::parse_quote! { A },
            r#trait: ::syn::parse_quote! { B },
        }
    );
}

#[derive(::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem)]
struct NoDebugInner {
    _a: i32,
    _b: ::std::string::String,
}

#[derive(::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem)]
struct NoDebug {
    _a: i32,
    _b: ::std::string::String,
    _c: NoDebugInner,
}

#[derive(::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem)]
enum NoDebugEnum {
    _A(NoDebug),
    _B(NoDebugInner),
}
