Skip to content

Commit

Permalink
Add tests in experimental off-chain env for multisig
Browse files Browse the repository at this point in the history
  • Loading branch information
cmichi committed Mar 1, 2022
1 parent e60baf2 commit 18ee448
Show file tree
Hide file tree
Showing 2 changed files with 374 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/multisig/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ std = [
"scale-info/std",
]
ink-as-dependency = []
ink-experimental-engine = ["ink_env/ink-experimental-engine"]
373 changes: 373 additions & 0 deletions examples/multisig/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ mod multisig {
assert!(0 < requirement && requirement <= owners && owners <= MAX_OWNERS);
}

#[cfg(not(feature = "ink-experimental-engine"))]
#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -1053,4 +1054,376 @@ mod multisig {
// Calling execute_transaction panics in any case.
}
}

#[cfg(feature = "ink-experimental-engine")]
#[cfg(test)]
mod tests_experimental_engine {
use super::*;
use ink_env::{
call,
test,
};
use ink_lang as ink;

const WALLET: [u8; 32] = [7; 32];

impl Transaction {
fn change_requirement(requirement: u32) -> Self {
let mut call = test::CallData::new(call::Selector::new([0x00; 4])); // change_requirement
call.push_arg(&requirement);
Self {
callee: AccountId::from(WALLET),
selector: call.selector().to_bytes(),
input: call.params().to_owned(),
transferred_value: 0,
gas_limit: 1000000,
}
}
}

fn set_sender(sender: AccountId) {
ink_env::test::set_caller::<Environment>(sender);
}

fn set_from_wallet() {
let callee = AccountId::from(WALLET);
set_sender(callee);
}

fn set_from_owner() {
let accounts = default_accounts();
set_sender(accounts.alice);
}

fn set_from_noowner() {
let accounts = default_accounts();
set_sender(accounts.django);
}

fn default_accounts() -> test::DefaultAccounts<Environment> {
ink_env::test::default_accounts::<Environment>()
}

fn build_contract() -> Multisig {
// Set the contract's address as `WALLET`.
let callee: AccountId = AccountId::from(WALLET);
ink_env::test::set_callee::<ink_env::DefaultEnvironment>(callee);

let accounts = default_accounts();
let owners = vec![accounts.alice, accounts.bob, accounts.eve];
Multisig::new(2, owners)
}

fn submit_transaction() -> Multisig {
let mut contract = build_contract();
let accounts = default_accounts();
set_from_owner();
contract.submit_transaction(Transaction::change_requirement(1));
assert_eq!(contract.transaction_list.transactions.len(), 1);
assert_eq!(test::recorded_events().count(), 2);
let transaction = contract.transactions.get(0).unwrap();
assert_eq!(transaction, Transaction::change_requirement(1));
contract.confirmations.get(&(0, accounts.alice)).unwrap();
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 1);
contract
}

#[ink::test]
fn construction_works() {
let accounts = default_accounts();
let owners = vec![accounts.alice, accounts.bob, accounts.eve];
let contract = build_contract();

assert_eq!(contract.owners.len(), 3);
assert_eq!(contract.requirement, 2);
assert!(contract.owners.iter().eq(owners.iter()));
assert!(contract.is_owner.get(&accounts.alice).is_some());
assert!(contract.is_owner.get(&accounts.bob).is_some());
assert!(contract.is_owner.get(&accounts.eve).is_some());
assert!(contract.is_owner.get(&accounts.charlie).is_none());
assert!(contract.is_owner.get(&accounts.django).is_none());
assert!(contract.is_owner.get(&accounts.frank).is_none());
assert_eq!(contract.transaction_list.transactions.len(), 0);
}

#[ink::test]
#[should_panic]
fn empty_owner_construction_fails() {
Multisig::new(0, vec![]);
}

#[ink::test]
#[should_panic]
fn zero_requirement_construction_fails() {
let accounts = default_accounts();
Multisig::new(0, vec![accounts.alice, accounts.bob]);
}

#[ink::test]
#[should_panic]
fn too_large_requirement_construction_fails() {
let accounts = default_accounts();
Multisig::new(3, vec![accounts.alice, accounts.bob]);
}

#[ink::test]
fn add_owner_works() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
let owners = contract.owners.len();
contract.add_owner(accounts.frank);
assert_eq!(contract.owners.len(), owners + 1);
assert!(contract.is_owner.get(&accounts.frank).is_some());
assert_eq!(test::recorded_events().count(), 1);
}

#[ink::test]
#[should_panic]
fn add_existing_owner_fails() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
contract.add_owner(accounts.bob);
}

#[ink::test]
#[should_panic]
fn add_owner_permission_denied() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_owner();
contract.add_owner(accounts.frank);
}

#[ink::test]
fn remove_owner_works() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
let owners = contract.owners.len();
contract.remove_owner(accounts.alice);
assert_eq!(contract.owners.len(), owners - 1);
assert!(contract.is_owner.get(&accounts.alice).is_none());
assert_eq!(test::recorded_events().count(), 1);
}

#[ink::test]
#[should_panic]
fn remove_owner_nonexisting_fails() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
contract.remove_owner(accounts.django);
}

#[ink::test]
#[should_panic]
fn remove_owner_permission_denied() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_owner();
contract.remove_owner(accounts.alice);
}

#[ink::test]
fn replace_owner_works() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
let owners = contract.owners.len();
contract.replace_owner(accounts.alice, accounts.django);
assert_eq!(contract.owners.len(), owners);
assert!(contract.is_owner.get(&accounts.alice).is_none());
assert!(contract.is_owner.get(&accounts.django).is_some());
assert_eq!(test::recorded_events().count(), 2);
}

#[ink::test]
#[should_panic]
fn replace_owner_existing_fails() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
contract.replace_owner(accounts.alice, accounts.bob);
}

#[ink::test]
#[should_panic]
fn replace_owner_nonexisting_fails() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_wallet();
contract.replace_owner(accounts.django, accounts.frank);
}

#[ink::test]
#[should_panic]
fn replace_owner_permission_denied() {
let accounts = default_accounts();
let mut contract = build_contract();
set_from_owner();
contract.replace_owner(accounts.alice, accounts.django);
}

#[ink::test]
fn change_requirement_works() {
let mut contract = build_contract();
assert_eq!(contract.requirement, 2);
set_from_wallet();
contract.change_requirement(3);
assert_eq!(contract.requirement, 3);
assert_eq!(test::recorded_events().count(), 1);
}

#[ink::test]
#[should_panic]
fn change_requirement_too_high() {
let mut contract = build_contract();
set_from_wallet();
contract.change_requirement(4);
}

#[ink::test]
#[should_panic]
fn change_requirement_zero_fails() {
let mut contract = build_contract();
set_from_wallet();
contract.change_requirement(0);
}

#[ink::test]
fn submit_transaction_works() {
submit_transaction();
}

#[ink::test]
#[should_panic]
fn submit_transaction_noowner_fails() {
let mut contract = build_contract();
set_from_noowner();
contract.submit_transaction(Transaction::change_requirement(1));
}

#[ink::test]
#[should_panic]
fn submit_transaction_wallet_fails() {
let mut contract = build_contract();
set_from_wallet();
contract.submit_transaction(Transaction::change_requirement(1));
}

#[ink::test]
fn cancel_transaction_works() {
let mut contract = submit_transaction();
set_from_wallet();
contract.cancel_transaction(0);
assert_eq!(contract.transaction_list.transactions.len(), 0);
assert_eq!(test::recorded_events().count(), 3);
}

#[ink::test]
fn cancel_transaction_nonexisting() {
let mut contract = submit_transaction();
set_from_wallet();
contract.cancel_transaction(1);
assert_eq!(contract.transaction_list.transactions.len(), 1);
assert_eq!(test::recorded_events().count(), 2);
}

#[ink::test]
#[should_panic]
fn cancel_transaction_no_permission() {
let mut contract = submit_transaction();
contract.cancel_transaction(0);
}

#[ink::test]
fn confirm_transaction_works() {
let mut contract = submit_transaction();
let accounts = default_accounts();
set_sender(accounts.bob);
contract.confirm_transaction(0);
assert_eq!(test::recorded_events().count(), 3);
contract.confirmations.get(&(0, accounts.bob)).unwrap();
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 2);
}

#[ink::test]
fn revoke_confirmations() {
// given
let mut contract = submit_transaction();
let accounts = default_accounts();
// Confirm by Bob
set_sender(accounts.bob);
contract.confirm_transaction(0);
// Confirm by Eve
set_sender(accounts.eve);
contract.confirm_transaction(0);
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 3);
// Revoke from Eve
contract.revoke_confirmation(0);
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 2);
// Revoke from Bob
set_sender(accounts.bob);
contract.revoke_confirmation(0);
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 1);
}

#[ink::test]
fn confirm_transaction_already_confirmed() {
let mut contract = submit_transaction();
let accounts = default_accounts();
set_sender(accounts.alice);
contract.confirm_transaction(0);
assert_eq!(test::recorded_events().count(), 2);
contract.confirmations.get(&(0, accounts.alice)).unwrap();
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 1);
}

#[ink::test]
#[should_panic]
fn confirm_transaction_noowner_fail() {
let mut contract = submit_transaction();
set_from_noowner();
contract.confirm_transaction(0);
}

#[ink::test]
fn revoke_transaction_works() {
let mut contract = submit_transaction();
let accounts = default_accounts();
set_sender(accounts.alice);
contract.revoke_confirmation(0);
assert_eq!(test::recorded_events().count(), 3);
assert!(contract.confirmations.get(&(0, accounts.alice)).is_none());
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 0);
}

#[ink::test]
fn revoke_transaction_no_confirmer() {
let mut contract = submit_transaction();
let accounts = default_accounts();
set_sender(accounts.bob);
contract.revoke_confirmation(0);
assert_eq!(test::recorded_events().count(), 2);
assert!(contract.confirmations.get(&(0, accounts.alice)).is_some());
assert_eq!(contract.confirmation_count.get(&0).unwrap(), 1);
}

#[ink::test]
#[should_panic]
fn revoke_transaction_noowner_fail() {
let mut contract = submit_transaction();
let accounts = default_accounts();
set_sender(accounts.django);
contract.revoke_confirmation(0);
}

#[ink::test]
fn execute_transaction_works() {
// Execution of calls is currently unsupported in off-chain test.
// Calling `execute_transaction` panics in any case.
}
}
}

0 comments on commit 18ee448

Please sign in to comment.