Skip to content

Commit

Permalink
tests rework
Browse files Browse the repository at this point in the history
  • Loading branch information
bekauz committed Jul 14, 2023
1 parent 5fdc426 commit 519315e
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 143 deletions.
1 change: 1 addition & 0 deletions contracts/holder/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub fn execute(
}
}

// this is tested in the LP module
/// should be sent to the LP token contract associated with the pool
/// to withdraw liquidity from
fn try_withdraw_liquidity(
Expand Down
2 changes: 1 addition & 1 deletion contracts/holder/src/suite_tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod tests;
// function where the assertion would otherwise happen.
macro_rules! is_error {
($x:expr, $e:expr) => {
assert!(format!("{:#}", $x.unwrap_err()).contains($e))
assert!(format!("{:#}", $x).contains($e))
};
}
pub(crate) use is_error;
Expand Down
29 changes: 18 additions & 11 deletions contracts/holder/src/suite_tests/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ impl SuiteBuilder {
self
}

pub fn with_funded_user(mut self, user: Addr, amount: Vec<Coin>) -> Self {
self.app = AppBuilder::new().build(|router, _, storage| {
router.bank.init_balance(storage, &user, amount).unwrap();
});
self
}

pub fn build(self) -> Suite {
let mut app = self.app;
let holder_code = app.store_code(holder_contract());
Expand Down Expand Up @@ -80,7 +73,7 @@ impl Suite {
&mut self,
caller: &str,
quantity: Vec<Coin>,
) -> anyhow::Result<AppResponse> {
) -> AppResponse {
self.app.execute_contract(
Addr::unchecked(caller),
self.holder.clone(),
Expand All @@ -89,6 +82,7 @@ impl Suite {
},
&[],
)
. unwrap()
}

/// sends a message on caller's behalf to withdraw remaining balance
Expand All @@ -110,13 +104,26 @@ impl Suite {
.query_wasm_smart(&self.holder, &QueryMsg::Withdrawer {})
.unwrap()
}

pub fn query_lp_address(&self) -> Addr {
self.app
.wrap()
.query_wasm_smart(&self.holder, &QueryMsg::LpAddress {})
.unwrap()
}
}

// helper
impl Suite {
pub fn fund_holder(&mut self, funder: Addr, tokens: Vec<Coin>) -> anyhow::Result<AppResponse> {
self.app.send_tokens(funder, self.holder.clone(), &tokens)
}
pub fn fund_holder(&mut self, tokens: Vec<Coin>) -> AppResponse {
self.app.sudo(cw_multi_test::SudoMsg::Bank(
cw_multi_test::BankSudo::Mint {
to_address: self.holder.to_string(),
amount: tokens,
},
))
.unwrap()
}

pub fn assert_holder_balance(&mut self, tokens: Vec<Coin>) {
for c in &tokens {
Expand Down
167 changes: 36 additions & 131 deletions contracts/holder/src/suite_tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use super::is_error;
use super::suite::{SuiteBuilder, DEFAULT_WITHDRAWER};
use cosmwasm_std::{coin, coins, Addr, Coin};
use cosmwasm_std::{coin, coins, Addr};

#[test]
fn test_instantiate_and_query_withdrawer() {
Expand Down Expand Up @@ -28,60 +27,23 @@ fn test_instantiate_invalid_lp_addr() {
}

#[test]
fn test_fund_contract_single_denom() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance = coins(1000, "coin");
#[should_panic(expected = "Unauthorized")]
fn test_withdraw_all_unauthorized() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract = coins(100, "coin");
suite
.fund_holder(user, amt_to_fund_contract.clone())
.unwrap();
suite.fund_holder(coins(100, "coin"));

// check that the holder contract balance has increased
suite.assert_holder_balance(amt_to_fund_contract);
// attacker attempts to withdraw, panic
suite.withdraw_all("attacker").unwrap();
}

#[test]
fn test_fund_and_withdraw_all_unauthorized() {
// create an attacker with an unauthorized address
let unauthorized = Addr::unchecked("attacker");

// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance = coins(1000, "coin");
fn test_withdraw_all_single_denom() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract = coins(100, "coin");
suite.fund_holder(user, amt_to_fund_contract).unwrap();

// attacker attempts to withdraw all
let resp = suite.withdraw_all(unauthorized.as_ref());
is_error!(resp, "Unauthorized");

// check to see the balance is unchanged
suite.assert_holder_balance(coins(100, "coin"));
}

#[test]
fn test_fund_and_withdraw_all_single_denom() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance = coins(1000, "coin");
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract = coins(100, "coin");
suite.fund_holder(user, amt_to_fund_contract).unwrap();
suite.fund_holder(coins(100, "coin"));

// withdraw all
suite.withdraw_all(DEFAULT_WITHDRAWER).unwrap();
Expand All @@ -94,135 +56,78 @@ fn test_fund_and_withdraw_all_single_denom() {
}

#[test]
fn test_fund_and_withdraw_all_two_denoms() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance: Vec<Coin> = vec![coin(100, "atom"), coin(90, "statom")];

fn test_withdraw_all_two_denoms() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract: Vec<Coin> = vec![coin(80, "atom"), coin(70, "statom")];

suite
.fund_holder(user, amt_to_fund_contract.clone())
.unwrap();
let balances = vec![coin(80, "atom"), coin(70, "statom")];
suite.fund_holder(balances.clone());

// withdraw all
suite.withdraw_all(DEFAULT_WITHDRAWER).unwrap();

// check to see there is no balance
let expected_balance: Vec<Coin> = vec![coin(0, "atom"), coin(0, "statom")];

suite.assert_holder_balance(expected_balance);

// check to see holder has received everythning
suite.assert_withdrawer_balance(amt_to_fund_contract);
// assert all funds are now in withdrawer address
suite.assert_holder_balance(vec![coin(0, "atom"), coin(0, "statom")]);
suite.assert_withdrawer_balance(balances);
}

#[test]
fn test_fund_and_withdraw_partial_single_denom() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance = coins(1000, "coin");
fn test_fund_single_withdraw_partial_single_denom() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract = coins(100, "coin");
suite.fund_holder(user, amt_to_fund_contract).unwrap();
suite.fund_holder(vec![coin(80, "atom")]);

// withdraw 75 out of a total of 100 tokens
suite
.withdraw_tokens(DEFAULT_WITHDRAWER, coins(75, "coin"))
.unwrap();
.withdraw_tokens(DEFAULT_WITHDRAWER, coins(75, "atom"));

// check to see there are 25 tokens left in contract
suite.assert_holder_balance(coins(25, "coin"));
suite.assert_holder_balance(coins(5, "atom"));

// and holder has received 75
suite.assert_withdrawer_balance(coins(75, "coin"));
suite.assert_withdrawer_balance(coins(75, "atom"));
}
#[test]
fn test_fund_and_withdraw_partial_two_denom() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance: Vec<Coin> = vec![coin(100, "atom"), coin(90, "statom")];

fn test_fund_multi_denom_withdraw_partial_two_denom() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract: Vec<Coin> = vec![coin(80, "atom"), coin(70, "statom")];
let balances = vec![coin(80, "atom"), coin(70, "statom")];
suite.fund_holder(balances);

suite.fund_holder(user, amt_to_fund_contract).unwrap();
let amt_to_withdraw = vec![coin(50, "atom"), coin(30, "statom")];

// withdraw partial
let amt_to_withdraw: Vec<Coin> = vec![coin(50, "atom"), coin(30, "statom")];

suite
.withdraw_tokens(DEFAULT_WITHDRAWER, amt_to_withdraw.clone())
.unwrap();

// check to see there is subtracted balance
let expected_balance: Vec<Coin> = vec![coin(30, "atom"), coin(40, "statom")];
suite.withdraw_tokens(DEFAULT_WITHDRAWER, amt_to_withdraw.clone());

let expected_balance = vec![coin(30, "atom"), coin(40, "statom")];
suite.assert_holder_balance(expected_balance);

// and that withdrawer has received withdrawn amount
suite.assert_withdrawer_balance(amt_to_withdraw);
}

#[test]
fn test_fund_and_withdraw_exact_single_denom() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance = coins(1000, "coin");
fn test_fund_multi_denom_withdraw_exact_single_denom() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();

// this user funds the holder contract
let amt_to_fund_contract = coins(100, "coin");
suite.fund_holder(user, amt_to_fund_contract).unwrap();
let balances = vec![coin(80, "atom"), coin(70, "stuatom")];
suite.fund_holder(balances);

// withdraw 100 out of a total of 100 tokens
suite
.withdraw_tokens(DEFAULT_WITHDRAWER, coins(100, "coin"))
.unwrap();
suite.withdraw_tokens(DEFAULT_WITHDRAWER, coins(70, "stuatom"));

// check to see there are 0 tokens left
suite.assert_holder_balance(coins(0, "coin"));
suite.assert_holder_balance(vec![coin(80, "atom")]);

// and withdrawer has them all
suite.assert_withdrawer_balance(coins(100, "coin"));
suite.assert_withdrawer_balance(coins(70, "stuatom"));
}

#[test]
fn test_fund_and_withdraw_too_big_single_denom() {
// set up an initial user with a balance in the test suite
let user = Addr::unchecked("anyuser");
let initial_user_balance = coins(1000, "coin");
#[should_panic(expected = "Cannot Sub with 70 and 100")]
fn test_fund_single_and_withdraw_too_big_single_denom() {
let mut suite = SuiteBuilder::default()
.with_funded_user(user.clone(), initial_user_balance)
.build();
let holder_balances = vec![coin(80, "atom"), coin(70, "statom")];
suite.fund_holder(holder_balances.clone());

// this user funds the holder contract
let amt_to_fund_contract = coins(100, "coin");
suite.fund_holder(user, amt_to_fund_contract).unwrap();

// try to withdraw 200 out of a total of 100 tokens
let resp = suite.withdraw_tokens(DEFAULT_WITHDRAWER, coins(200, "coin"));
// the dispatched bank send message should fail and everything should roll back
is_error!(resp, "error executing WasmMsg");

// check to see all tokens are intact
suite.assert_holder_balance(coins(100, "coin"));

// and withdrawer has not received anything
suite.assert_withdrawer_balance(coins(0, "coin"));
suite.withdraw_tokens(DEFAULT_WITHDRAWER, coins(100, "statom"));
}

0 comments on commit 519315e

Please sign in to comment.