use crate::*;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(feature = "std")]
use std::boxed::Box;
#[derive(Default, Clone)]
pub struct ChainMetaTest {
pub(crate) slot_time: Option<SlotTime>,
}
#[derive(Debug, Clone)]
pub struct TestPolicy {
position: usize,
policy: OwnedPolicy,
}
impl TestPolicy {
fn new(policy: OwnedPolicy) -> Self {
Self {
position: 0,
policy,
}
}
}
#[derive(Default, Clone)]
#[doc(hidden)]
pub struct CommonDataTest<'a> {
pub(crate) metadata: ChainMetaTest,
pub(crate) parameter: Option<&'a [u8]>,
pub(crate) policies: Option<Vec<TestPolicy>>,
}
#[derive(Default, Clone)]
pub struct ContextTest<'a, C> {
pub(crate) common: CommonDataTest<'a>,
pub(crate) custom: C,
}
pub type InitContextTest<'a> = ContextTest<'a, InitOnlyDataTest>;
#[derive(Default)]
#[doc(hidden)]
pub struct InitOnlyDataTest {
init_origin: Option<AccountAddress>,
}
pub type ReceiveContextTest<'a> = ContextTest<'a, ReceiveOnlyDataTest>;
#[derive(Default)]
#[doc(hidden)]
pub struct ReceiveOnlyDataTest {
pub(crate) invoker: Option<AccountAddress>,
pub(crate) self_address: Option<ContractAddress>,
pub(crate) self_balance: Option<Amount>,
pub(crate) sender: Option<Address>,
pub(crate) owner: Option<AccountAddress>,
}
impl ChainMetaTest {
pub fn empty() -> Self { Default::default() }
pub fn set_slot_time(&mut self, value: SlotTime) -> &mut Self {
self.slot_time = Some(value);
self
}
}
impl<'a, C> ContextTest<'a, C> {
pub fn push_policy(&mut self, value: OwnedPolicy) -> &mut Self {
if let Some(policies) = self.common.policies.as_mut() {
policies.push(TestPolicy::new(value));
} else {
self.common.policies = Some(vec![TestPolicy::new(value)])
}
self
}
pub fn empty_policies(&mut self) -> &mut Self {
self.common.policies = Some(Vec::new());
self
}
pub fn set_parameter(&mut self, value: &'a [u8]) -> &mut Self {
self.common.parameter = Some(value);
self
}
pub fn metadata_mut(&mut self) -> &mut ChainMetaTest { &mut self.common.metadata }
pub fn set_metadata_slot_time(&mut self, value: SlotTime) -> &mut Self {
self.metadata_mut().set_slot_time(value);
self
}
}
impl<'a> InitContextTest<'a> {
pub fn empty() -> Self { Default::default() }
pub fn set_init_origin(&mut self, value: AccountAddress) -> &mut Self {
self.custom.init_origin = Some(value);
self
}
}
impl<'a> ReceiveContextTest<'a> {
pub fn empty() -> Self { Default::default() }
pub fn set_invoker(&mut self, value: AccountAddress) -> &mut Self {
self.custom.invoker = Some(value);
self
}
pub fn set_self_address(&mut self, value: ContractAddress) -> &mut Self {
self.custom.self_address = Some(value);
self
}
pub fn set_self_balance(&mut self, value: Amount) -> &mut Self {
self.custom.self_balance = Some(value);
self
}
pub fn set_sender(&mut self, value: Address) -> &mut Self {
self.custom.sender = Some(value);
self
}
pub fn set_owner(&mut self, value: AccountAddress) -> &mut Self {
self.custom.owner = Some(value);
self
}
}
fn unwrap_ctx_field<A>(opt: Option<A>, name: &str) -> A {
match opt {
Some(v) => v,
None => fail!(
"Unset field on test context '{}', make sure to set all the field necessary for the \
contract",
name
),
}
}
impl HasChainMetadata for ChainMetaTest {
fn slot_time(&self) -> SlotTime { unwrap_ctx_field(self.slot_time, "metadata.slot_time") }
}
impl HasPolicy for TestPolicy {
fn identity_provider(&self) -> IdentityProvider { self.policy.identity_provider }
fn created_at(&self) -> Timestamp { self.policy.created_at }
fn valid_to(&self) -> Timestamp { self.policy.valid_to }
fn next_item(&mut self, buf: &mut [u8; 31]) -> Option<(AttributeTag, u8)> {
if let Some(item) = self.policy.items.get(self.position) {
let len = item.1.len();
buf[0..len].copy_from_slice(&item.1);
self.position += 1;
Some((item.0, len as u8))
} else {
None
}
}
}
impl<'a, C> HasCommonData for ContextTest<'a, C> {
type MetadataType = ChainMetaTest;
type ParamType = Cursor<&'a [u8]>;
type PolicyIteratorType = crate::vec::IntoIter<TestPolicy>;
type PolicyType = TestPolicy;
fn parameter_cursor(&self) -> Self::ParamType {
Cursor::new(unwrap_ctx_field(self.common.parameter, "parameter"))
}
fn metadata(&self) -> &Self::MetadataType { &self.common.metadata }
fn policies(&self) -> Self::PolicyIteratorType {
unwrap_ctx_field(self.common.policies.clone(), "policies").into_iter()
}
}
impl<'a> HasInitContext for InitContextTest<'a> {
type InitData = ();
fn open(_data: Self::InitData) -> Self { InitContextTest::default() }
fn init_origin(&self) -> AccountAddress {
unwrap_ctx_field(self.custom.init_origin, "init_origin")
}
}
impl<'a> HasReceiveContext for ReceiveContextTest<'a> {
type ReceiveData = ();
fn open(_data: Self::ReceiveData) -> Self { ReceiveContextTest::default() }
fn invoker(&self) -> AccountAddress { unwrap_ctx_field(self.custom.invoker, "invoker") }
fn self_address(&self) -> ContractAddress {
unwrap_ctx_field(self.custom.self_address, "self_address")
}
fn self_balance(&self) -> Amount { unwrap_ctx_field(self.custom.self_balance, "self_balance") }
fn sender(&self) -> Address { unwrap_ctx_field(self.custom.sender, "sender") }
fn owner(&self) -> AccountAddress { unwrap_ctx_field(self.custom.owner, "owner") }
}
impl<'a> HasParameter for Cursor<&'a [u8]> {
fn size(&self) -> u32 { self.data.len() as u32 }
}
pub struct LogRecorder {
pub logs: Vec<Vec<u8>>,
}
impl HasLogger for LogRecorder {
fn init() -> Self {
Self {
logs: Vec::new(),
}
}
fn log_bytes(&mut self, event: &[u8]) { self.logs.push(event.to_vec()) }
}
#[derive(Eq, PartialEq, Debug)]
pub enum ActionsTree {
Accept,
SimpleTransfer {
to: AccountAddress,
amount: Amount,
},
Send {
to: ContractAddress,
receive_name: String,
amount: Amount,
parameter: Vec<u8>,
},
AndThen {
left: Box<ActionsTree>,
right: Box<ActionsTree>,
},
OrElse {
left: Box<ActionsTree>,
right: Box<ActionsTree>,
},
}
impl HasActions for ActionsTree {
fn accept() -> Self { ActionsTree::Accept }
fn simple_transfer(acc: &AccountAddress, amount: Amount) -> Self {
ActionsTree::SimpleTransfer {
to: *acc,
amount,
}
}
fn send(ca: &ContractAddress, receive_name: &str, amount: Amount, parameter: &[u8]) -> Self {
ActionsTree::Send {
to: *ca,
receive_name: receive_name.to_string(),
amount,
parameter: parameter.to_vec(),
}
}
fn and_then(self, then: Self) -> Self {
ActionsTree::AndThen {
left: Box::new(self),
right: Box::new(then),
}
}
fn or_else(self, el: Self) -> Self {
ActionsTree::OrElse {
left: Box::new(self),
right: Box::new(el),
}
}
}
#[doc(hidden)]
#[cfg(all(feature = "wasm-test", target_arch = "wasm32"))]
pub fn report_error(message: &str, filename: &str, line: u32, column: u32) {
let msg_bytes = message.as_bytes();
let filename_bytes = filename.as_bytes();
unsafe {
crate::prims::report_error(
msg_bytes.as_ptr(),
msg_bytes.len() as u32,
filename_bytes.as_ptr(),
filename_bytes.len() as u32,
line,
column,
)
};
}
#[doc(hidden)]
#[cfg(not(all(feature = "wasm-test", target_arch = "wasm32")))]
pub fn report_error(_message: &str, _filename: &str, _line: u32, _column: u32) {}