Skip to content

Commit

Permalink
Merge pull request #81 from CosmWasm/test-mock-api
Browse files Browse the repository at this point in the history
Add tests for `MockApi` in `App`
  • Loading branch information
DariuszDepta authored Oct 10, 2023
2 parents 34a2c9d + 6d1984b commit 5fb2039
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 27 deletions.
35 changes: 21 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 9 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,23 @@ cosmwasm_1_3 = ["cosmwasm_1_2", "cosmwasm-std/cosmwasm_1_3"]
cosmwasm_1_4 = ["cosmwasm_1_3", "cosmwasm-std/cosmwasm_1_4"]

[dependencies]
cw-utils = "1.0.2"
anyhow = "1.0.75"
cosmwasm-std = { version = "1.4.1", features = ["staking", "stargate"] }
cw-storage-plus = "1.1.0"
cosmwasm-std = { version = "1.4.0", features = ["staking", "stargate"] }
cw-utils = "1.0.2"
derivative = "2.2.0"
itertools = "0.11.0"
prost = "0.12.1"
schemars = "0.8.15"
serde = { version = "1.0.188", default-features = false, features = ["derive"] }
prost = "0.12.1"
anyhow = "1.0.75"
thiserror = "1.0.49"
derivative = "2.2.0"
sha2 = "0.10.8"
thiserror = "1.0.49"

[dev-dependencies]
bech32 = "0.9.1"
once_cell = "1.18.0"
sha2 = "0.10.8"

# We don't use these dependencies directly,
# we tighten versions that builds with `-Zminimal-versions` work.
ecdsa = "0.16.8"
38 changes: 31 additions & 7 deletions src/tests/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ use crate::test_helpers::echo::EXECUTE_REPLY_BASE_ID;
use crate::test_helpers::{caller, echo, error, hackatom, payout, reflect, CustomMsg};
use crate::transactions::{transactional, StorageTransaction};
use crate::wasm::ContractData;
use crate::AppBuilder;
use crate::{
custom_app, next_block, App, AppResponse, Bank, CosmosRouter, Distribution, Executor, Module,
Router, Staking, Wasm, WasmSudo,
};
use cosmwasm_std::testing::{mock_env, MockApi, MockQuerier};
use cosmwasm_std::testing::{mock_env, MockQuerier};
use cosmwasm_std::{
coin, coins, from_slice, to_binary, Addr, AllBalanceResponse, Api, Attribute, BankMsg,
BankQuery, Binary, BlockInfo, Coin, CosmosMsg, CustomQuery, Empty, Event, OverflowError,
Expand Down Expand Up @@ -1631,22 +1632,19 @@ mod wasm_queries {

mod custom_messages {
use super::*;
use crate::AppBuilder;

#[test]
fn triggering_custom_msg() {
let api = MockApi::default();
let sender = api.addr_validate("sender").unwrap();
let owner = api.addr_validate("owner").unwrap();

let custom_handler = CachingCustomHandler::<CustomMsg, Empty>::new();
let custom_handler_state = custom_handler.state();

let mut app = AppBuilder::new_custom()
.with_api(api)
.with_custom(custom_handler)
.build(no_init);

let sender = app.api().addr_validate("sender").unwrap();
let owner = app.api().addr_validate("owner").unwrap();

let contract_id = app.store_code(echo::custom_contract());

let contract = app
Expand Down Expand Up @@ -1972,3 +1970,29 @@ mod errors {
assert_eq!(err.chain().count(), 4);
}
}

mod api {
use super::*;

#[test]
fn api_addr_validate_should_work() {
let app = App::default();
let addr = app.api().addr_validate("creator").unwrap();
assert_eq!(addr.to_string(), "creator");
}

#[test]
#[cfg(not(feature = "cosmwasm_1_5"))]
fn api_addr_canonicalize_should_work() {
let app = App::default();
let canonical = app.api().addr_canonicalize("creator").unwrap();
assert_eq!(canonical.to_string(), "0000000000000000000000000000726F0000000000000000000000000000000000000000006572000000000000000000000000000000000000000000610000000000000000000000000000000000000000006374000000000000");
}

#[test]
fn api_addr_humanize_should_work() {
let app = App::default();
let canonical = app.api().addr_canonicalize("creator").unwrap();
assert_eq!(app.api().addr_humanize(&canonical).unwrap(), "creator");
}
}
1 change: 1 addition & 0 deletions tests/app_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::marker::PhantomData;

mod with_api;
mod with_bank;
mod with_block;
mod with_distribution;
Expand Down
139 changes: 139 additions & 0 deletions tests/app_builder/with_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use bech32::{decode, encode, FromBase32, ToBase32, Variant};
use cosmwasm_std::{
Addr, Api, CanonicalAddr, HexBinary, RecoverPubkeyError, StdError, StdResult, VerificationError,
};
use cw_multi_test::AppBuilder;
use sha2::{Digest, Sha256};

struct MyApi {
prefix: &'static str,
}

impl MyApi {
fn new(prefix: &'static str) -> Self {
Self { prefix }
}
}

impl Api for MyApi {
fn addr_validate(&self, input: &str) -> StdResult<Addr> {
let canonical = self.addr_canonicalize(input)?;
let normalized = self.addr_humanize(&canonical)?;
if input != normalized {
Err(StdError::generic_err(
"Invalid input: address not normalized",
))
} else {
Ok(Addr::unchecked(input))
}
}

fn addr_canonicalize(&self, input: &str) -> StdResult<CanonicalAddr> {
if let Ok((prefix, decoded, Variant::Bech32)) = decode(input) {
if prefix == self.prefix {
if let Ok(bytes) = Vec::<u8>::from_base32(&decoded) {
return Ok(bytes.into());
}
}
}
Err(StdError::generic_err("Invalid input"))
}

fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
if let Ok(encoded) = encode(
self.prefix,
canonical.as_slice().to_base32(),
Variant::Bech32,
) {
Ok(Addr::unchecked(encoded))
} else {
Err(StdError::generic_err("Invalid canonical address"))
}
}

fn secp256k1_verify(
&self,
_message_hash: &[u8],
_signature: &[u8],
_public_key: &[u8],
) -> Result<bool, VerificationError> {
unimplemented!()
}

fn secp256k1_recover_pubkey(
&self,
_message_hash: &[u8],
_signature: &[u8],
_recovery_param: u8,
) -> Result<Vec<u8>, RecoverPubkeyError> {
unimplemented!()
}

fn ed25519_verify(
&self,
_message: &[u8],
_signature: &[u8],
_public_key: &[u8],
) -> Result<bool, VerificationError> {
unimplemented!()
}

fn ed25519_batch_verify(
&self,
_messages: &[&[u8]],
_signatures: &[&[u8]],
_public_keys: &[&[u8]],
) -> Result<bool, VerificationError> {
unimplemented!()
}

fn debug(&self, _message: &str) {
unimplemented!()
}
}

impl MyApi {
fn addr_make(&self, input: &str) -> Addr {
let digest = Sha256::digest(input).to_vec();
match encode(self.prefix, digest.to_base32(), Variant::Bech32) {
Ok(address) => Addr::unchecked(address),
Err(reason) => panic!("Generating address failed with reason: {reason}"),
}
}
}

#[test]
fn building_app_with_custom_api_should_work() {
// prepare test data
let human = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp";
let hex = "bc6bfd848ebd7819c9a82bf124d65e7f739d08e002601e23bb906aacd40a3d81";

// create application with custom api that implements
// Bech32 address encoding with 'juno' prefix
let app = AppBuilder::default()
.with_api(MyApi::new("juno"))
.build(|_, _, _| {});

// check address validation function
assert_eq!(
app.api().addr_validate(human).unwrap(),
Addr::unchecked(human)
);

// check if address can be canonicalized
assert_eq!(
app.api().addr_canonicalize(human).unwrap(),
CanonicalAddr::from(HexBinary::from_hex(hex).unwrap())
);

// check if address can be humanized
assert_eq!(
app.api()
.addr_humanize(&app.api().addr_canonicalize(human).unwrap())
.unwrap(),
Addr::unchecked(human)
);

// check extension function for creating Bech32 encoded addresses
assert_eq!(app.api().addr_make("creator"), Addr::unchecked(human));
}

0 comments on commit 5fb2039

Please sign in to comment.