use super::{
EnvInstance,
OnInstance,
};
use crate::{
Environment,
Result,
};
use core::fmt::Debug;
use ink_engine::test_api::RecordedDebugMessages;
use std::panic::UnwindSafe;
pub use super::call_data::CallData;
pub use ink_engine::ChainExtension;
#[derive(Clone)]
pub struct EmittedEvent {
pub topics: Vec<Vec<u8>>,
pub data: Vec<u8>,
}
pub fn set_account_balance<T>(account_id: T::AccountId, new_balance: T::Balance)
where
T: Environment<Balance = u128>, {
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.set_balance(scale::Encode::encode(&account_id), new_balance);
})
}
pub fn get_account_balance<T>(account_id: T::AccountId) -> Result<T::Balance>
where
T: Environment<Balance = u128>, {
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.get_balance(scale::Encode::encode(&account_id))
.map_err(Into::into)
})
}
pub fn register_chain_extension<E>(extension: E)
where
E: ink_engine::ChainExtension + 'static,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.chain_extension_handler
.register(Box::new(extension));
})
}
pub fn set_block_entropy<T>(_entropy: T::Hash) -> Result<()>
where
T: Environment,
{
unimplemented!("off-chain environment does not yet support `set_block_entropy`");
}
pub fn recorded_debug_messages() -> RecordedDebugMessages {
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.get_emitted_debug_messages()
})
}
pub fn set_clear_storage_disabled(_disable: bool) {
unimplemented!(
"off-chain environment does not yet support `set_clear_storage_disabled`"
);
}
pub fn advance_block<T>()
where
T: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.advance_block();
})
}
pub fn set_caller<T>(caller: T::AccountId)
where
T: Environment,
<T as Environment>::AccountId: From<[u8; 32]>,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.set_caller(scale::Encode::encode(&caller));
})
}
pub fn set_callee<T>(callee: T::AccountId)
where
T: Environment,
<T as Environment>::AccountId: From<[u8; 32]>,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.set_callee(scale::Encode::encode(&callee));
})
}
pub fn callee<T>() -> T::AccountId
where
T: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
let callee = instance.engine.get_callee();
scale::Decode::decode(&mut &callee[..]).expect("encoding failed")
})
}
pub fn get_contract_storage_rw<T>(account_id: &T::AccountId) -> (usize, usize)
where
T: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.get_contract_storage_rw(scale::Encode::encode(&account_id))
})
}
pub fn set_balance<T>(account_id: T::AccountId, new_balance: T::Balance)
where
T: Environment<Balance = u128>, <T as Environment>::AccountId: From<[u8; 32]>,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.set_balance(scale::Encode::encode(&account_id), new_balance);
})
}
pub fn set_value_transferred<T>(value: T::Balance)
where
T: Environment<Balance = u128>, {
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.set_value_transferred(value);
})
}
pub fn count_used_storage_cells<T>(account_id: &T::AccountId) -> Result<usize>
where
T: Environment,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.count_used_storage_cells(&scale::Encode::encode(&account_id))
.map_err(Into::into)
})
}
pub fn run_test<T, F>(f: F) -> Result<()>
where
T: Environment,
F: FnOnce(DefaultAccounts<T>) -> Result<()>,
<T as Environment>::AccountId: From<[u8; 32]>,
{
let default_accounts = default_accounts::<T>();
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.initialize_or_reset();
let encoded_alice = scale::Encode::encode(&default_accounts.alice);
instance.engine.set_caller(encoded_alice.clone());
instance.engine.set_callee(encoded_alice.clone());
let substantial = 1_000_000;
let some = 1_000;
instance.engine.set_balance(encoded_alice, substantial);
instance
.engine
.set_balance(scale::Encode::encode(&default_accounts.bob), some);
instance
.engine
.set_balance(scale::Encode::encode(&default_accounts.charlie), some);
instance
.engine
.set_balance(scale::Encode::encode(&default_accounts.django), 0);
instance
.engine
.set_balance(scale::Encode::encode(&default_accounts.eve), 0);
instance
.engine
.set_balance(scale::Encode::encode(&default_accounts.frank), 0);
});
f(default_accounts)
}
pub fn default_accounts<T>() -> DefaultAccounts<T>
where
T: Environment,
<T as Environment>::AccountId: From<[u8; 32]>,
{
DefaultAccounts {
alice: T::AccountId::from([0x01; 32]),
bob: T::AccountId::from([0x02; 32]),
charlie: T::AccountId::from([0x03; 32]),
django: T::AccountId::from([0x04; 32]),
eve: T::AccountId::from([0x05; 32]),
frank: T::AccountId::from([0x06; 32]),
}
}
pub struct DefaultAccounts<T>
where
T: Environment,
{
pub alice: T::AccountId,
pub bob: T::AccountId,
pub charlie: T::AccountId,
pub django: T::AccountId,
pub eve: T::AccountId,
pub frank: T::AccountId,
}
pub fn recorded_events() -> impl Iterator<Item = EmittedEvent> {
<EnvInstance as OnInstance>::on_instance(|instance| {
instance
.engine
.get_emitted_events()
.into_iter()
.map(|evt: ink_engine::test_api::EmittedEvent| evt.into())
})
}
pub fn assert_contract_termination<T, F>(
should_terminate: F,
expected_beneficiary: T::AccountId,
expected_value_transferred_to_beneficiary: T::Balance,
) where
T: Environment,
F: FnMut() + UnwindSafe,
<T as Environment>::AccountId: Debug,
<T as Environment>::Balance: Debug,
{
let value_any = ::std::panic::catch_unwind(should_terminate)
.expect_err("contract did not terminate");
let encoded_input = value_any
.downcast_ref::<Vec<u8>>()
.expect("panic object can not be cast");
let (value_transferred, encoded_beneficiary): (T::Balance, Vec<u8>) =
scale::Decode::decode(&mut &encoded_input[..]).expect("input can not be decoded");
let beneficiary =
<T::AccountId as scale::Decode>::decode(&mut &encoded_beneficiary[..])
.expect("input can not be decoded");
assert_eq!(value_transferred, expected_value_transferred_to_beneficiary);
assert_eq!(beneficiary, expected_beneficiary);
}