use serde::{Deserialize, Serialize};
use crate::schemars::{self, JsonSchema};
use crate::cosmwasm_std::{Addr, Coin};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct MockEnv {
pub sent_funds: Vec<Coin>,
pub(crate) sender: Addr,
pub(crate) contract: Addr
}
impl MockEnv {
pub const MAX_ADDRESS_LEN: usize = 54;
pub fn new(sender: impl Into<String>, contract: impl Into<String>) -> Self {
let sender = sender.into();
let contract = contract.into();
if !is_valid_address(&sender) || !is_valid_address(&contract) {
panic!(
"Addresses must be at most {} bytes long and have all lower case characters.",
MockEnv::MAX_ADDRESS_LEN
);
}
Self {
sender: Addr::unchecked(sender),
contract: Addr::unchecked(contract),
sent_funds: vec![]
}
}
#[inline]
pub fn sent_funds(mut self, funds: Vec<Coin>) -> Self {
self.sent_funds = funds;
self
}
#[inline]
pub fn sender(&self) -> &str {
self.sender.as_str()
}
#[inline]
pub fn contract(&self) -> &str {
self.contract.as_str()
}
pub(crate) fn new_sanitized(
sender: impl Into<String>,
contract: impl Into<String>
) -> Self {
let sender = sender.into();
assert!(is_valid_address(&sender));
let mut contract = contract.into();
contract.truncate(Self::MAX_ADDRESS_LEN);
Self {
sender: Addr::unchecked(sender),
contract: Addr::unchecked(contract.to_lowercase()),
sent_funds: vec![]
}
}
}
#[inline]
fn is_valid_address(addr: &str) -> bool {
addr.len() <= MockEnv::MAX_ADDRESS_LEN &&
addr.to_lowercase() == addr
}
#[cfg(test)]
mod tests {
use crate::cosmwasm_std::{testing::MockApi, Api};
use super::*;
#[test]
fn verify_cw_mock_api_max_len() {
let addr = "a".repeat(MockEnv::MAX_ADDRESS_LEN + 1);
let api = MockApi::default();
api.addr_canonicalize(&addr).unwrap_err();
api.addr_canonicalize(&addr[0..addr.len() - 1]).unwrap();
}
#[test]
fn verify_cw_mock_api_converts_to_lowercase() {
let addr = "A".repeat(MockEnv::MAX_ADDRESS_LEN);
let api = MockApi::default();
let canon = api.addr_canonicalize(&addr).unwrap();
assert!(canon.0.iter().all(|x| *x == 97));
let human = api.addr_humanize(&canon).unwrap();
assert!(human.as_bytes().iter().all(|x| *x == 97));
assert!(is_valid_address(human.as_str()));
}
#[test]
fn mock_env_respects_mock_api() {
let addr = "A".repeat(MockEnv::MAX_ADDRESS_LEN + 1);
assert!(!is_valid_address(&addr));
let env = MockEnv::new_sanitized("sender", addr);
assert_eq!(env.sender.as_str(), "sender");
assert_eq!(env.contract.as_str(), "a".repeat(MockEnv::MAX_ADDRESS_LEN));
assert!(is_valid_address(env.sender.as_str()));
assert!(is_valid_address(env.contract.as_str()));
}
#[test]
fn addresses_can_contain_spaces_and_special_characters() {
MockEnv::new("`~123!@#$%^&*()-=+\\/.,<>?[]{}", "this address has spaces");
}
}