use crate::wasm_emulation::channel::RemoteChannel;
use crate::{
App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule,
Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper,
};
use anyhow::Result as AnyResult;
use cosmwasm_std::testing::{mock_env, MockApi, MockStorage};
use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage};
use serde::de::DeserializeOwned;
use std::fmt::Debug;
pub type BasicAppBuilder<ExecC, QueryC> = AppBuilder<
BankKeeper,
MockApi,
MockStorage,
FailingModule<ExecC, QueryC, Empty>,
WasmKeeper<ExecC, QueryC>,
StakeKeeper,
DistributionKeeper,
IbcFailingModule,
GovFailingModule,
>;
pub struct AppBuilder<Bank, Api, Storage, Custom, Wasm, Staking, Distr, Ibc, Gov> {
api: Api,
block: BlockInfo,
storage: Storage,
bank: Bank,
wasm: Wasm,
custom: Custom,
staking: Staking,
distribution: Distr,
ibc: Ibc,
gov: Gov,
remote: Option<RemoteChannel>,
}
impl Default
for AppBuilder<
BankKeeper,
MockApi,
MockStorage,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcFailingModule,
GovFailingModule,
>
{
fn default() -> Self {
Self::new()
}
}
impl
AppBuilder<
BankKeeper,
MockApi,
MockStorage,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcFailingModule,
GovFailingModule,
>
{
pub fn new() -> Self {
AppBuilder {
api: MockApi::default(),
block: mock_env().block,
storage: MockStorage::new(),
bank: BankKeeper::new(),
wasm: WasmKeeper::new(),
custom: FailingModule::new("custom"),
staking: StakeKeeper::new(),
distribution: DistributionKeeper::new(),
ibc: IbcFailingModule::new("ibc"),
gov: GovFailingModule::new("gov"),
remote: None,
}
}
}
impl<ExecC, QueryC>
AppBuilder<
BankKeeper,
MockApi,
MockStorage,
FailingModule<ExecC, QueryC, Empty>,
WasmKeeper<ExecC, QueryC>,
StakeKeeper,
DistributionKeeper,
IbcFailingModule,
GovFailingModule,
>
where
ExecC: CustomMsg + DeserializeOwned + 'static,
QueryC: Debug + CustomQuery + DeserializeOwned + 'static,
{
pub fn new_custom() -> Self {
AppBuilder {
api: MockApi::default(),
block: mock_env().block,
storage: MockStorage::new(),
bank: BankKeeper::new(),
wasm: WasmKeeper::new(),
custom: FailingModule::new("custom"),
staking: StakeKeeper::new(),
distribution: DistributionKeeper::new(),
ibc: IbcFailingModule::new("ibc"),
gov: GovFailingModule::new("gov"),
remote: None,
}
}
}
impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
where
CustomT: Module,
WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
CustomT::QueryT: CustomQuery,
{
pub fn with_wasm<NewWasm: Wasm<CustomT::ExecT, CustomT::QueryT>>(
self,
wasm: NewWasm,
) -> AppBuilder<BankT, ApiT, StorageT, CustomT, NewWasm, StakingT, DistrT, IbcT, GovT> {
let AppBuilder {
bank,
api,
storage,
custom,
block,
staking,
distribution,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_bank<NewBank: Bank>(
self,
bank: NewBank,
) -> AppBuilder<NewBank, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
let AppBuilder {
wasm,
api,
storage,
custom,
block,
staking,
distribution,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_api<NewApi: Api>(
self,
api: NewApi,
) -> AppBuilder<BankT, NewApi, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
let AppBuilder {
wasm,
bank,
storage,
custom,
block,
staking,
distribution,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_storage<NewStorage: Storage>(
self,
storage: NewStorage,
) -> AppBuilder<BankT, ApiT, NewStorage, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
let AppBuilder {
wasm,
api,
bank,
custom,
block,
staking,
distribution,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_custom<NewCustom: Module>(
self,
custom: NewCustom,
) -> AppBuilder<BankT, ApiT, StorageT, NewCustom, WasmT, StakingT, DistrT, IbcT, GovT> {
let AppBuilder {
wasm,
bank,
api,
storage,
block,
staking,
distribution,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_staking<NewStaking: Staking>(
self,
staking: NewStaking,
) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, NewStaking, DistrT, IbcT, GovT> {
let AppBuilder {
wasm,
api,
storage,
custom,
block,
bank,
distribution,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_distribution<NewDistribution: Distribution>(
self,
distribution: NewDistribution,
) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, NewDistribution, IbcT, GovT>
{
let AppBuilder {
wasm,
api,
storage,
custom,
block,
staking,
bank,
ibc,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_ibc<NewIbc: Ibc>(
self,
ibc: NewIbc,
) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, NewIbc, GovT> {
let AppBuilder {
wasm,
api,
storage,
custom,
block,
staking,
bank,
distribution,
gov,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_gov<NewGov: Gov>(
self,
gov: NewGov,
) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, NewGov> {
let AppBuilder {
wasm,
api,
storage,
custom,
block,
staking,
bank,
distribution,
ibc,
remote,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
gov,
remote,
}
}
pub fn with_remote(
self,
remote: RemoteChannel,
) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
let AppBuilder {
wasm,
api,
storage,
custom,
block,
staking,
bank,
distribution,
ibc,
gov,
..
} = self;
AppBuilder {
api,
block,
storage,
bank,
wasm,
custom,
staking,
distribution,
ibc,
remote: Some(remote),
gov,
}
}
pub fn with_block(mut self, block: BlockInfo) -> Self {
self.block = block;
self
}
#[allow(clippy::type_complexity)]
pub fn build<F>(
self,
init_fn: F,
) -> AnyResult<App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>>
where
BankT: Bank,
ApiT: Api,
StorageT: Storage,
CustomT: Module,
WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
StakingT: Staking,
DistrT: Distribution,
IbcT: Ibc,
GovT: Gov,
F: FnOnce(
&mut Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>,
&dyn Api,
&mut dyn Storage,
),
{
let router = Router {
wasm: self.wasm,
bank: self.bank,
custom: self.custom,
staking: self.staking,
distribution: self.distribution,
ibc: self.ibc,
gov: self.gov,
};
let mut app = App {
router,
api: self.api,
block: self.block,
storage: self.storage,
remote: self.remote.ok_or(anyhow::anyhow!(
"Remote has to be defined to use clone-testing"
))?,
};
app.init_modules(init_fn);
Ok(app)
}
}