//! > Test valid expansion of a simple starknet contract.

//! > test_runner_name
ExpandContractTestRunner(expect_diagnostics: false)

//! > cairo_code
#[starknet::contract]
mod test_contract {
    #[storage]
    struct Storage {}

    #[l1_handler]
    fn good_l1_handler(ref self: ContractState, from_address: felt252, arg: felt252) {}

    #[l1_handler]
    fn good_l1_handler_ignored(ref self: ContractState, _from_address: felt252, arg: felt252) {}
}

//! > generated_cairo_code
lib.cairo:

#[starknet::contract]
mod test_contract {
    #[storage]
    struct Storage {}

    #[l1_handler]
    fn good_l1_handler(ref self: ContractState, from_address: felt252, arg: felt252) {}

    #[l1_handler]
    fn good_l1_handler_ignored(ref self: ContractState, _from_address: felt252, arg: felt252) {}
}

lib.cairo:1:1
#[starknet::contract]
^^^^^^^^^^^^^^^^^^^^^
contract:

#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {}


#[phantom]
pub struct Storage {
}

#[derive(Drop, Copy)]
#[doc(hidden)]
pub struct StorageStorageBase {
}
#[doc(hidden)]
impl StorageStorageImpl of starknet::storage::StorageTrait<Storage> {
    type BaseType = StorageStorageBase;
    fn storage(self: starknet::storage::FlattenedStorage<Storage>) -> StorageStorageBase {
        StorageStorageBase {
        }
    }
}
#[derive(Drop, Copy)]
#[doc(hidden)]
pub struct StorageStorageBaseMut {
}
#[doc(hidden)]
impl StorageStorageMutImpl of starknet::storage::StorageTraitMut<Storage> {
    type BaseType = StorageStorageBaseMut;
    fn storage_mut(self: starknet::storage::FlattenedStorage<starknet::storage::Mutable::<Storage>>) -> StorageStorageBaseMut {
        StorageStorageBaseMut {
        }
    }
}

pub struct ContractState {
}

impl ContractStateDrop of Drop<ContractState> {}
 
impl ContractStateDeref of core::ops::Deref<@ContractState> {
    type Target = starknet::storage::FlattenedStorage<Storage>;
    fn deref(self: @ContractState) -> starknet::storage::FlattenedStorage<Storage> {
        starknet::storage::FlattenedStorage {}
    }
}
impl ContractStateDerefMut of core::ops::DerefMut<ContractState> {
    type Target = starknet::storage::FlattenedStorage<starknet::storage::Mutable<Storage>> ;
    fn deref_mut(ref self: ContractState) -> starknet::storage::FlattenedStorage<starknet::storage::Mutable<Storage>> {
        starknet::storage::FlattenedStorage {}
    }
}
pub fn unsafe_new_contract_state() -> ContractState {
    ContractState {
    }
}
#[cfg(target: 'test')]
#[inline(always)]
pub fn contract_state_for_testing() -> ContractState {
    unsafe_new_contract_state()
}

// TODO(Gil): This generates duplicate diagnostics because of the plugin system, squash the duplicates into one.
#[deprecated(
    feature: "deprecated_legacy_map",
    note: "Use `starknet::storage::Map` instead."
)]
#[allow(unused_imports)]
use starknet::storage::Map as LegacyMap;
#[cfg(target: 'test')]
pub const TEST_CLASS_HASH: starknet::ClassHash = 0x32a1956d182625bfe7f9834635d01441624366b326c190ecbf557e699f94b76.try_into().unwrap();

#[doc(hidden)]
#[implicit_precedence(core::pedersen::Pedersen, core::RangeCheck, core::integer::Bitwise, core::ec::EcOp, core::poseidon::Poseidon, core::SegmentArena, core::circuit::RangeCheck96, core::circuit::AddMod, core::circuit::MulMod, core::gas::GasBuiltin, System)]
fn __wrapper__good_l1_handler(mut data: Span::<felt252>) -> Span::<felt252> {
    core::internal::require_implicit::<System>();
    core::internal::revoke_ap_tracking();
    core::option::OptionTraitImpl::expect(core::gas::withdraw_gas(), 'Out of gas');
    let __arg_from_address = core::option::OptionTraitImpl::expect(
        core::serde::Serde::<felt252>::deserialize(ref data),
        'Failed to deserialize param #1'
    );
    let __arg_arg = core::option::OptionTraitImpl::expect(
        core::serde::Serde::<felt252>::deserialize(ref data),
        'Failed to deserialize param #2'
    );
    assert(core::array::SpanTrait::is_empty(data), 'Input too long for arguments');
    core::option::OptionTraitImpl::expect(
        core::gas::withdraw_gas_all(core::gas::get_builtin_costs()), 'Out of gas',
    );
    let mut contract_state = unsafe_new_contract_state();
    good_l1_handler(ref contract_state, __arg_from_address, __arg_arg);
    let mut arr = ArrayTrait::new();
    // References.
    // Result.
    core::array::ArrayTrait::span(@arr)
}

#[doc(hidden)]
#[implicit_precedence(core::pedersen::Pedersen, core::RangeCheck, core::integer::Bitwise, core::ec::EcOp, core::poseidon::Poseidon, core::SegmentArena, core::circuit::RangeCheck96, core::circuit::AddMod, core::circuit::MulMod, core::gas::GasBuiltin, System)]
fn __wrapper__good_l1_handler_ignored(mut data: Span::<felt252>) -> Span::<felt252> {
    core::internal::require_implicit::<System>();
    core::internal::revoke_ap_tracking();
    core::option::OptionTraitImpl::expect(core::gas::withdraw_gas(), 'Out of gas');
    let __arg__from_address = core::option::OptionTraitImpl::expect(
        core::serde::Serde::<felt252>::deserialize(ref data),
        'Failed to deserialize param #1'
    );
    let __arg_arg = core::option::OptionTraitImpl::expect(
        core::serde::Serde::<felt252>::deserialize(ref data),
        'Failed to deserialize param #2'
    );
    assert(core::array::SpanTrait::is_empty(data), 'Input too long for arguments');
    core::option::OptionTraitImpl::expect(
        core::gas::withdraw_gas_all(core::gas::get_builtin_costs()), 'Out of gas',
    );
    let mut contract_state = unsafe_new_contract_state();
    good_l1_handler_ignored(ref contract_state, __arg__from_address, __arg_arg);
    let mut arr = ArrayTrait::new();
    // References.
    // Result.
    core::array::ArrayTrait::span(@arr)
}


pub mod __external {
}
pub mod __l1_handler {
    pub use super::__wrapper__good_l1_handler as good_l1_handler;
    pub use super::__wrapper__good_l1_handler_ignored as good_l1_handler_ignored;
}
pub mod __constructor {
}
    impl ContractStateEventEmitter of starknet::event::EventEmitter<
        ContractState, Event
    > {
        fn emit<S, impl IntoImp: core::traits::Into<S, Event>>(
            ref self: ContractState, event: S
        ) {
            let event: Event = core::traits::Into::into(event);
            let mut keys = Default::<core::array::Array>::default();
            let mut data = Default::<core::array::Array>::default();
            starknet::Event::append_keys_and_data(@event, ref keys, ref data);
            starknet::SyscallResultTrait::unwrap_syscall(
                starknet::syscalls::emit_event_syscall(
                    core::array::ArrayTrait::span(@keys),
                    core::array::ArrayTrait::span(@data),
                )
            )
        }
    }



lib.cairo:1:1
#[starknet::contract]
^^^^^^^^^^^^^^^^^^^^^
impls:

impl EventDrop<> of core::traits::Drop::<Event>;


lib.cairo:1:1
#[starknet::contract]
^^^^^^^^^^^^^^^^^^^^^
starknet_derive:

impl EventIsEvent of starknet::Event<Event> {
    fn append_keys_and_data(
        self: @Event, ref keys: Array<felt252>, ref data: Array<felt252>
    ) {
        match self {
        }
    }
    fn deserialize(
        ref keys: Span<felt252>, ref data: Span<felt252>,
    ) -> Option<Event> {
        let __selector__ = *core::array::SpanTrait::pop_front(ref keys)?;
        Option::None
    }
}



lib.cairo:3:5
    #[storage]
    ^^^^^^^^^^
impls:

impl StorageStorageBaseDrop<> of core::traits::Drop::<StorageStorageBase>;
impl StorageStorageBaseCopy<> of core::traits::Copy::<StorageStorageBase>;


lib.cairo:3:5
    #[storage]
    ^^^^^^^^^^
impls:

impl StorageStorageBaseMutDrop<> of core::traits::Drop::<StorageStorageBaseMut>;
impl StorageStorageBaseMutCopy<> of core::traits::Copy::<StorageStorageBaseMut>;

//! > expected_diagnostics

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

//! > Test erroneous expansion of a simple starknet contract.

//! > test_runner_name
ExpandContractTestRunner(expect_diagnostics: true)

//! > cairo_code
#[starknet::contract]
mod test_contract {
    #[l1_handler]
    fn l1_handler_no_params(ref self: ContractState) {}

    #[l1_handler]
    fn l1_handler_wrong_first_param_name(ref self: ContractState, abc: felt252) {}

    #[l1_handler]
    fn l1_handler_wrong_first_param_type(ref self: ContractState, from_address: u128) {}
}

//! > generated_cairo_code
lib.cairo:

#[starknet::contract]
mod test_contract {
    #[l1_handler]
    fn l1_handler_no_params(ref self: ContractState) {}

    #[l1_handler]
    fn l1_handler_wrong_first_param_name(ref self: ContractState, abc: felt252) {}

    #[l1_handler]
    fn l1_handler_wrong_first_param_type(ref self: ContractState, from_address: u128) {}
}

//! > expected_diagnostics
error: Plugin diagnostic: Contracts must define a 'Storage' struct.
 --> lib.cairo:1:1-11:1
  #[starknet::contract]
 _^
| ...
| }
|_^

error[E0006]: Type not found.
 --> lib.cairo:4:39
    fn l1_handler_no_params(ref self: ContractState) {}
                                      ^^^^^^^^^^^^^

error[E0006]: Type not found.
 --> lib.cairo:7:52
    fn l1_handler_wrong_first_param_name(ref self: ContractState, abc: felt252) {}
                                                   ^^^^^^^^^^^^^

error[E0006]: Type not found.
 --> lib.cairo:10:52
    fn l1_handler_wrong_first_param_type(ref self: ContractState, from_address: u128) {}
                                                   ^^^^^^^^^^^^^
