//! > Test expansion of derive.

//! > test_runner_name
test_expand_plugin(expect_diagnostics: false)

//! > cairo_code
#[derive(Copy, Debug, Default, Drop, Hash)]
struct A {}

#[derive(Copy, Debug, Default, Drop, Hash)]
struct B {}

#[derive(Clone, Debug, Default, Destruct, Hash, PanicDestruct, PartialEq, Serde)]
struct TwoMemberStruct {
    a: A,
    b: B,
}

#[derive(Copy, Debug, Destruct, PanicDestruct, Default, Hash)]
struct GenericStruct<T> {
    a: T,
}


trait SomeTrait<T, U> {}

#[derive(Drop, Debug, Clone, PartialEq, Serde, Hash)]
struct TwoMemberGenericStruct<T, U, impl USomeTrait: SomeTrait<U, T>> {
    a: T,
    b: U,
}

#[derive(Clone, Debug, Default, Destruct, Hash, PanicDestruct, PartialEq, Serde)]
enum TwoVariantEnum {
    First: A,
    #[default]
    Second: B,
}

#[derive(Copy, Drop)]
extern type ExternType;

//! > expanded_cairo_code
#[derive(Copy, Debug, Default, Drop, Hash)]
struct A {}

#[derive(Copy, Debug, Default, Drop, Hash)]
struct B {}

#[derive(Clone, Debug, Default, Destruct, Hash, PanicDestruct, PartialEq, Serde)]
struct TwoMemberStruct {
    a: A,
    b: B,
}

#[derive(Copy, Debug, Destruct, PanicDestruct, Default, Hash)]
struct GenericStruct<T> {
    a: T,
}


trait SomeTrait<T, U> {}

#[derive(Drop, Debug, Clone, PartialEq, Serde, Hash)]
struct TwoMemberGenericStruct<T, U, impl USomeTrait: SomeTrait<U, T>> {
    a: T,
    b: U,
}

#[derive(Clone, Debug, Default, Destruct, Hash, PanicDestruct, PartialEq, Serde)]
enum TwoVariantEnum {
    First: A,
    #[default]
    Second: B,
}

#[derive(Copy, Drop)]
extern type ExternType;
impl ACopy of core::traits::Copy::<A>;
impl ADebug of core::fmt::Debug::<A> {
    fn fmt(self: @A, ref f: core::fmt::Formatter) -> core::result::Result::<(), core::fmt::Error> {
        write!(f, "A {{")?;
        write!(f, " }}")
    }
}
impl ADefault of core::traits::Default::<A> {
    fn default() -> A {
        A {
            
        }
    }
}
impl ADrop of core::traits::Drop::<A>;
impl AHash<
    __State,
    impl __SHashState: core::hash::HashStateTrait<__State>,
    +Drop<__State>
> of core::hash::Hash<A, __State, __SHashState> {
    #[inline(always)]
    fn update_state(state: __State, value: A) -> __State {
        
        state
    }
}
impl BCopy of core::traits::Copy::<B>;
impl BDebug of core::fmt::Debug::<B> {
    fn fmt(self: @B, ref f: core::fmt::Formatter) -> core::result::Result::<(), core::fmt::Error> {
        write!(f, "B {{")?;
        write!(f, " }}")
    }
}
impl BDefault of core::traits::Default::<B> {
    fn default() -> B {
        B {
            
        }
    }
}
impl BDrop of core::traits::Drop::<B>;
impl BHash<
    __State,
    impl __SHashState: core::hash::HashStateTrait<__State>,
    +Drop<__State>
> of core::hash::Hash<B, __State, __SHashState> {
    #[inline(always)]
    fn update_state(state: __State, value: B) -> __State {
        
        state
    }
}
impl TwoMemberStructClone of core::clone::Clone::<TwoMemberStruct> {
    fn clone(self: @TwoMemberStruct) -> TwoMemberStruct {
        TwoMemberStruct {
            a: core::clone::Clone::clone(self.a),
            b: core::clone::Clone::clone(self.b),
        }
    }
}
impl TwoMemberStructDebug of core::fmt::Debug::<TwoMemberStruct> {
    fn fmt(self: @TwoMemberStruct, ref f: core::fmt::Formatter) -> core::result::Result::<(), core::fmt::Error> {
        write!(f, "TwoMemberStruct {{")?;
        write!(f, " a: ")?;
        core::fmt::Debug::fmt(self.a, ref f)?;
        write!(f, ",")?;
        write!(f, " b: ")?;
        core::fmt::Debug::fmt(self.b, ref f)?;
        write!(f, " }}")
    }
}
impl TwoMemberStructDefault of core::traits::Default::<TwoMemberStruct> {
    fn default() -> TwoMemberStruct {
        TwoMemberStruct {
            a: core::traits::Default::default(),
            b: core::traits::Default::default(),
        }
    }
}
impl TwoMemberStructDestruct of core::traits::Destruct::<TwoMemberStruct> {
    fn destruct(self: TwoMemberStruct) nopanic {
        let TwoMemberStruct { a, b } = self;
        core::traits::Destruct::destruct(a);
        core::traits::Destruct::destruct(b);
    }
}
impl TwoMemberStructHash<
    __State,
    impl __SHashState: core::hash::HashStateTrait<__State>,
    +Drop<__State>
> of core::hash::Hash<TwoMemberStruct, __State, __SHashState> {
    #[inline(always)]
    fn update_state(state: __State, value: TwoMemberStruct) -> __State {
        let state = core::hash::Hash::update_state(state, value.a);
        let state = core::hash::Hash::update_state(state, value.b);
        state
    }
}
impl TwoMemberStructPanicDestruct of core::traits::PanicDestruct::<TwoMemberStruct> {
    fn panic_destruct(self: TwoMemberStruct, ref panic: Panic) nopanic {
        let TwoMemberStruct { a, b } = self;
        core::traits::PanicDestruct::panic_destruct(a, ref panic);
        core::traits::PanicDestruct::panic_destruct(b, ref panic);
    }
}
impl TwoMemberStructPartialEq of core::traits::PartialEq::<TwoMemberStruct> {
    fn eq(lhs: @TwoMemberStruct, rhs: @TwoMemberStruct) -> bool {
        lhs.a == rhs.a && lhs.b == rhs.b
    }
}
impl TwoMemberStructSerde of core::serde::Serde::<TwoMemberStruct> {
    fn serialize(self: @TwoMemberStruct, ref output: core::array::Array<felt252>) {
        core::serde::Serde::serialize(self.a, ref output);
        core::serde::Serde::serialize(self.b, ref output)
    }
    fn deserialize(ref serialized: core::array::Span<felt252>) -> core::option::Option<TwoMemberStruct> {
        core::option::Option::Some(TwoMemberStruct {
            a: core::serde::Serde::deserialize(ref serialized)?,
            b: core::serde::Serde::deserialize(ref serialized)?,
        })
    }
}
impl GenericStructCopy<T, +core::traits::Copy<T>> of core::traits::Copy::<GenericStruct<T>>;
impl GenericStructDebug<T, +core::fmt::Debug<T>> of core::fmt::Debug::<GenericStruct<T>> {
    fn fmt(self: @GenericStruct<T>, ref f: core::fmt::Formatter) -> core::result::Result::<(), core::fmt::Error> {
        write!(f, "GenericStruct {{")?;
        write!(f, " a: ")?;
        core::fmt::Debug::fmt(self.a, ref f)?;
        write!(f, " }}")
    }
}
impl GenericStructDestruct<T, +core::traits::Destruct<T>> of core::traits::Destruct::<GenericStruct<T>> {
    fn destruct(self: GenericStruct<T>) nopanic {
        let GenericStruct { a } = self;
        core::traits::Destruct::destruct(a);
    }
}
impl GenericStructPanicDestruct<T, +core::traits::PanicDestruct<T>> of core::traits::PanicDestruct::<GenericStruct<T>> {
    fn panic_destruct(self: GenericStruct<T>, ref panic: Panic) nopanic {
        let GenericStruct { a } = self;
        core::traits::PanicDestruct::panic_destruct(a, ref panic);
    }
}
impl GenericStructDefault<T, +core::traits::Default<T>, +core::traits::Destruct<T>> of core::traits::Default::<GenericStruct<T>> {
    fn default() -> GenericStruct<T> {
        GenericStruct {
            a: core::traits::Default::default(),
        }
    }
}
impl GenericStructHash<
    __State,
    impl __SHashState: core::hash::HashStateTrait<__State>,
    +Drop<__State>,
    T, +core::hash::Hash<T, __State, __SHashState>, +Drop<T>
> of core::hash::Hash<GenericStruct<T>, __State, __SHashState> {
    #[inline(always)]
    fn update_state(state: __State, value: GenericStruct<T>) -> __State {
        let state = core::hash::Hash::update_state(state, value.a);
        state
    }
}
impl TwoMemberGenericStructDrop<T, U, impl USomeTrait: SomeTrait<U, T>, +core::traits::Drop<T>, +core::traits::Drop<U>> of core::traits::Drop::<TwoMemberGenericStruct<T, U, USomeTrait>>;
impl TwoMemberGenericStructDebug<T, U, impl USomeTrait: SomeTrait<U, T>, +core::fmt::Debug<T>, +core::fmt::Debug<U>> of core::fmt::Debug::<TwoMemberGenericStruct<T, U, USomeTrait>> {
    fn fmt(self: @TwoMemberGenericStruct<T, U, USomeTrait>, ref f: core::fmt::Formatter) -> core::result::Result::<(), core::fmt::Error> {
        write!(f, "TwoMemberGenericStruct {{")?;
        write!(f, " a: ")?;
        core::fmt::Debug::fmt(self.a, ref f)?;
        write!(f, ",")?;
        write!(f, " b: ")?;
        core::fmt::Debug::fmt(self.b, ref f)?;
        write!(f, " }}")
    }
}
impl TwoMemberGenericStructClone<T, U, impl USomeTrait: SomeTrait<U, T>, +core::clone::Clone<T>, +Destruct<T>, +core::clone::Clone<U>, +Destruct<U>> of core::clone::Clone::<TwoMemberGenericStruct<T, U, USomeTrait>> {
    fn clone(self: @TwoMemberGenericStruct<T, U, USomeTrait>) -> TwoMemberGenericStruct<T, U, USomeTrait> {
        TwoMemberGenericStruct {
            a: core::clone::Clone::clone(self.a),
            b: core::clone::Clone::clone(self.b),
        }
    }
}
impl TwoMemberGenericStructPartialEq<T, U, impl USomeTrait: SomeTrait<U, T>, +core::traits::PartialEq<T>, +core::traits::PartialEq<U>> of core::traits::PartialEq::<TwoMemberGenericStruct<T, U, USomeTrait>> {
    fn eq(lhs: @TwoMemberGenericStruct<T, U, USomeTrait>, rhs: @TwoMemberGenericStruct<T, U, USomeTrait>) -> bool {
        lhs.a == rhs.a && lhs.b == rhs.b
    }
}
impl TwoMemberGenericStructSerde<T, U, impl USomeTrait: SomeTrait<U, T>, +core::serde::Serde<T>, +core::traits::Destruct<T>, +core::serde::Serde<U>, +core::traits::Destruct<U>> of core::serde::Serde::<TwoMemberGenericStruct<T, U, USomeTrait>> {
    fn serialize(self: @TwoMemberGenericStruct<T, U, USomeTrait>, ref output: core::array::Array<felt252>) {
        core::serde::Serde::serialize(self.a, ref output);
        core::serde::Serde::serialize(self.b, ref output)
    }
    fn deserialize(ref serialized: core::array::Span<felt252>) -> core::option::Option<TwoMemberGenericStruct<T, U, USomeTrait>> {
        core::option::Option::Some(TwoMemberGenericStruct {
            a: core::serde::Serde::deserialize(ref serialized)?,
            b: core::serde::Serde::deserialize(ref serialized)?,
        })
    }
}
impl TwoMemberGenericStructHash<
    __State,
    impl __SHashState: core::hash::HashStateTrait<__State>,
    +Drop<__State>,
    T, U, impl USomeTrait: SomeTrait<U, T>, +core::hash::Hash<T, __State, __SHashState>, +Drop<T>, +core::hash::Hash<U, __State, __SHashState>, +Drop<U>
> of core::hash::Hash<TwoMemberGenericStruct<T, U, USomeTrait>, __State, __SHashState> {
    #[inline(always)]
    fn update_state(state: __State, value: TwoMemberGenericStruct<T, U, USomeTrait>) -> __State {
        let state = core::hash::Hash::update_state(state, value.a);
        let state = core::hash::Hash::update_state(state, value.b);
        state
    }
}
impl TwoVariantEnumClone of core::clone::Clone::<TwoVariantEnum> {
    fn clone(self: @TwoVariantEnum) -> TwoVariantEnum {
        match self {
            TwoVariantEnum::First(x) => TwoVariantEnum::First(core::clone::Clone::clone(x)),
            TwoVariantEnum::Second(x) => TwoVariantEnum::Second(core::clone::Clone::clone(x)),
        }
    }
}
impl TwoVariantEnumDebug of core::fmt::Debug::<TwoVariantEnum> {
    fn fmt(self: @TwoVariantEnum, ref f: core::fmt::Formatter) -> core::result::Result::<(), core::fmt::Error> {
        match self {
            TwoVariantEnum::First(x) => {
                write!(f, "TwoVariantEnum::First(")?;
                core::fmt::Debug::fmt(x, ref f)?;
                write!(f, ")")
            },

            TwoVariantEnum::Second(x) => {
                write!(f, "TwoVariantEnum::Second(")?;
                core::fmt::Debug::fmt(x, ref f)?;
                write!(f, ")")
            },

        }
    }
}
impl TwoVariantEnumDefault of core::traits::Default::<TwoVariantEnum> {
    fn default() -> TwoVariantEnum {
        TwoVariantEnum::Second(core::traits::Default::default())
    }
}
impl TwoVariantEnumDestruct of core::traits::Destruct::<TwoVariantEnum> {
    fn destruct(self: TwoVariantEnum) nopanic {
        match self {
            TwoVariantEnum::First(x) => core::traits::Destruct::destruct(x),
            TwoVariantEnum::Second(x) => core::traits::Destruct::destruct(x),
        }
    }
}
impl TwoVariantEnumHash<
    __State,
    impl __SHashState: core::hash::HashStateTrait<__State>,
    +Drop<__State>
> of core::hash::Hash<TwoVariantEnum, __State, __SHashState> {
    #[inline(always)]
    fn update_state(state: __State, value: TwoVariantEnum) -> __State {
        match value {
            TwoVariantEnum::First(x) => {
                let state = core::hash::Hash::update_state(state, 0);
                core::hash::Hash::update_state(state, x)
            },
            TwoVariantEnum::Second(x) => {
                let state = core::hash::Hash::update_state(state, 1);
                core::hash::Hash::update_state(state, x)
            },
        }
    }
}
impl TwoVariantEnumPanicDestruct of core::traits::PanicDestruct::<TwoVariantEnum> {
    fn panic_destruct(self: TwoVariantEnum, ref panic: Panic) nopanic {
        match self {
            TwoVariantEnum::First(x) => core::traits::PanicDestruct::panic_destruct(x, ref panic),
            TwoVariantEnum::Second(x) => core::traits::PanicDestruct::panic_destruct(x, ref panic),
        }
    }
}
impl TwoVariantEnumPartialEq of core::traits::PartialEq::<TwoVariantEnum> {
    fn eq(lhs: @TwoVariantEnum, rhs: @TwoVariantEnum) -> bool {
        match lhs {
            TwoVariantEnum::First(x) => match rhs {
                TwoVariantEnum::First(y) => x == y,
                TwoVariantEnum::Second(_y) => false,
            },
            TwoVariantEnum::Second(x) => match rhs {
                TwoVariantEnum::First(_y) => false,
                TwoVariantEnum::Second(y) => x == y,
            },
        }
    }
}
impl TwoVariantEnumSerde of core::serde::Serde::<TwoVariantEnum> {
    fn serialize(self: @TwoVariantEnum, ref output: core::array::Array<felt252>) {
        match self {
            TwoVariantEnum::First(x) => { core::serde::Serde::serialize(@0, ref output); core::serde::Serde::serialize(x, ref output); },
            TwoVariantEnum::Second(x) => { core::serde::Serde::serialize(@1, ref output); core::serde::Serde::serialize(x, ref output); },
        }
    }
    fn deserialize(ref serialized: core::array::Span<felt252>) -> core::option::Option<TwoVariantEnum> {
        let idx: felt252 = core::serde::Serde::deserialize(ref serialized)?;
        core::option::Option::Some(
            match idx {
                0 => TwoVariantEnum::First(core::serde::Serde::deserialize(ref serialized)?),
                1 => TwoVariantEnum::Second(core::serde::Serde::deserialize(ref serialized)?),
                _ => { return core::option::Option::None; }
            }
        )
    }
}
impl ExternTypeCopy of core::traits::Copy::<ExternType>;
impl ExternTypeDrop of core::traits::Drop::<ExternType>;

//! > expected_diagnostics

//! > ==========================================================================

//! > Test diagnostics of derive.

//! > test_runner_name
test_expand_plugin(expect_diagnostics: true)

//! > cairo_code
#[derive()]
struct EmptyArgs {}

#[derive(1)]
struct NotPath {}

#[derive(Unsupported)]
struct UnsupportedTrait {}

#[derive(long::path)]
struct NonSimplePath {}

#[derive(Clone)]
extern type NotClonable;

#[derive(Default)]
enum NoDefaultValue {
    First,
    Second,
}

#[derive(Default)]
enum TooManyDefaultValues {
    #[default]
    First,
    #[default]
    Second,
}

//! > expanded_cairo_code
#[derive()]
struct EmptyArgs {}

#[derive(1)]
struct NotPath {}

#[derive(Unsupported)]
struct UnsupportedTrait {}

#[derive(long::path)]
struct NonSimplePath {}

#[derive(Clone)]
extern type NotClonable;

#[derive(Default)]
enum NoDefaultValue {
    First,
    Second,
}

#[derive(Default)]
enum TooManyDefaultValues {
    #[default]
    First,
    #[default]
    Second,
}
impl TooManyDefaultValuesDefault of core::traits::Default::<TooManyDefaultValues> {
    fn default() -> TooManyDefaultValues {
        TooManyDefaultValues::First(core::traits::Default::default())
    }
}

//! > expected_diagnostics
error: Expected args.
 --> test_src/lib.cairo:1:9
#[derive()]
        ^^

error: Expected path.
 --> test_src/lib.cairo:4:10
#[derive(1)]
         ^

error: Unsupported trait for derive for extern types.
 --> test_src/lib.cairo:13:10
#[derive(Clone)]
         ^***^

error: derive `Default` for enum only supported with a default variant.
 --> test_src/lib.cairo:16:10
#[derive(Default)]
         ^*****^

error: Multiple variants annotated with `#[default]`
 --> test_src/lib.cairo:26:5
    #[default]
    ^********^
