abstract_cw_multi_test/
app_builder.rs

1//! AppBuilder helps you set up your test blockchain environment step by step [App].
2use crate::featured::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking};
3use crate::ibc::IbcSimpleModule;
4use crate::{
5    App, Bank, BankKeeper, FailingModule, Gov, GovFailingModule, Ibc, Module, Router, Stargate,
6    StargateFailing, Wasm, WasmKeeper,
7};
8use cosmwasm_std::testing::{mock_env, MockApi, MockStorage};
9use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage};
10use serde::de::DeserializeOwned;
11use std::fmt::Debug;
12
13/// This is essential to create a custom app with custom module.
14///
15/// # Example
16///
17/// ```
18/// # use cosmwasm_std::Empty;
19/// # use cw_multi_test::{no_init, BasicAppBuilder, FailingModule, Module};
20/// # type MyHandler = FailingModule<Empty, Empty, Empty>;
21/// # type MyExecC = Empty;
22/// # type MyQueryC = Empty;
23///
24/// let mut app = BasicAppBuilder::<MyExecC, MyQueryC>::new_custom()
25///                   .with_custom(MyHandler::default())
26///                   .build(no_init);
27/// ```
28/// This type alias is crucial for constructing a custom app with specific modules.
29/// It provides a streamlined approach to building and configuring an App tailored to
30/// particular testing needs or scenarios.
31pub type BasicAppBuilder<ExecC, QueryC> = AppBuilder<
32    BankKeeper,
33    MockApi,
34    MockStorage,
35    FailingModule<ExecC, QueryC, Empty>,
36    WasmKeeper<ExecC, QueryC>,
37    StakeKeeper,
38    DistributionKeeper,
39    IbcSimpleModule,
40    GovFailingModule,
41    StargateFailing,
42>;
43
44/// Utility to build [App] in stages.
45/// When particular properties are not explicitly set, then default values are used.
46pub struct AppBuilder<Bank, Api, Storage, Custom, Wasm, Staking, Distr, Ibc, Gov, Stargate> {
47    api: Api,
48    block: BlockInfo,
49    storage: Storage,
50    bank: Bank,
51    wasm: Wasm,
52    custom: Custom,
53    staking: Staking,
54    distribution: Distr,
55    ibc: Ibc,
56    gov: Gov,
57    stargate: Stargate,
58}
59
60impl Default
61    for AppBuilder<
62        BankKeeper,
63        MockApi,
64        MockStorage,
65        FailingModule<Empty, Empty, Empty>,
66        WasmKeeper<Empty, Empty>,
67        StakeKeeper,
68        DistributionKeeper,
69        IbcSimpleModule,
70        GovFailingModule,
71        StargateFailing,
72    >
73{
74    fn default() -> Self {
75        Self::new()
76    }
77}
78
79impl
80    AppBuilder<
81        BankKeeper,
82        MockApi,
83        MockStorage,
84        FailingModule<Empty, Empty, Empty>,
85        WasmKeeper<Empty, Empty>,
86        StakeKeeper,
87        DistributionKeeper,
88        IbcSimpleModule,
89        GovFailingModule,
90        StargateFailing,
91    >
92{
93    /// Creates builder with default components working with empty exec and query messages.
94    pub fn new() -> Self {
95        AppBuilder {
96            api: MockApi::default(),
97            block: mock_env().block,
98            storage: MockStorage::new(),
99            bank: BankKeeper::new(),
100            wasm: WasmKeeper::new(),
101            custom: FailingModule::new(),
102            staking: StakeKeeper::new(),
103            distribution: DistributionKeeper::new(),
104            ibc: IbcSimpleModule,
105            gov: GovFailingModule::new(),
106            stargate: StargateFailing,
107        }
108    }
109}
110
111impl<ExecC, QueryC>
112    AppBuilder<
113        BankKeeper,
114        MockApi,
115        MockStorage,
116        FailingModule<ExecC, QueryC, Empty>,
117        WasmKeeper<ExecC, QueryC>,
118        StakeKeeper,
119        DistributionKeeper,
120        IbcSimpleModule,
121        GovFailingModule,
122        StargateFailing,
123    >
124where
125    ExecC: CustomMsg + DeserializeOwned + 'static,
126    QueryC: Debug + CustomQuery + DeserializeOwned + 'static,
127{
128    /// Creates builder with default components designed to work with custom exec and query
129    /// messages.
130    pub fn new_custom() -> Self {
131        AppBuilder {
132            api: MockApi::default(),
133            block: mock_env().block,
134            storage: MockStorage::new(),
135            bank: BankKeeper::new(),
136            wasm: WasmKeeper::new(),
137            custom: FailingModule::new(),
138            staking: StakeKeeper::new(),
139            distribution: DistributionKeeper::new(),
140            ibc: IbcSimpleModule,
141            gov: GovFailingModule::new(),
142            stargate: StargateFailing,
143        }
144    }
145}
146
147impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
148    AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
149where
150    CustomT: Module,
151    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
152{
153    /// Overwrites the default wasm executor.
154    ///
155    /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need
156    /// to be bound to Bank or Custom yet - as those may change. The cross-components validation is
157    /// done on final building.
158    pub fn with_wasm<NewWasm: Wasm<CustomT::ExecT, CustomT::QueryT>>(
159        self,
160        wasm: NewWasm,
161    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, NewWasm, StakingT, DistrT, IbcT, GovT, StargateT>
162    {
163        let AppBuilder {
164            bank,
165            api,
166            storage,
167            custom,
168            block,
169            staking,
170            distribution,
171            ibc,
172            gov,
173            stargate,
174            ..
175        } = self;
176
177        AppBuilder {
178            api,
179            block,
180            storage,
181            bank,
182            wasm,
183            custom,
184            staking,
185            distribution,
186            ibc,
187            gov,
188            stargate,
189        }
190    }
191
192    /// Overwrites the default bank interface.
193    pub fn with_bank<NewBank: Bank>(
194        self,
195        bank: NewBank,
196    ) -> AppBuilder<NewBank, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
197    {
198        let AppBuilder {
199            wasm,
200            api,
201            storage,
202            custom,
203            block,
204            staking,
205            distribution,
206            ibc,
207            gov,
208            stargate,
209            ..
210        } = self;
211
212        AppBuilder {
213            api,
214            block,
215            storage,
216            bank,
217            wasm,
218            custom,
219            staking,
220            distribution,
221            ibc,
222            gov,
223            stargate,
224        }
225    }
226
227    /// Overwrites the default api interface.
228    pub fn with_api<NewApi: Api>(
229        self,
230        api: NewApi,
231    ) -> AppBuilder<BankT, NewApi, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
232    {
233        let AppBuilder {
234            wasm,
235            bank,
236            storage,
237            custom,
238            block,
239            staking,
240            distribution,
241            ibc,
242            gov,
243            stargate,
244            ..
245        } = self;
246
247        AppBuilder {
248            api,
249            block,
250            storage,
251            bank,
252            wasm,
253            custom,
254            staking,
255            distribution,
256            ibc,
257            gov,
258            stargate,
259        }
260    }
261
262    /// Overwrites the default storage interface.
263    pub fn with_storage<NewStorage: Storage>(
264        self,
265        storage: NewStorage,
266    ) -> AppBuilder<BankT, ApiT, NewStorage, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
267    {
268        let AppBuilder {
269            wasm,
270            api,
271            bank,
272            custom,
273            block,
274            staking,
275            distribution,
276            ibc,
277            gov,
278            stargate,
279            ..
280        } = self;
281
282        AppBuilder {
283            api,
284            block,
285            storage,
286            bank,
287            wasm,
288            custom,
289            staking,
290            distribution,
291            ibc,
292            gov,
293            stargate,
294        }
295    }
296
297    /// Overwrites the default handler for custom messages.
298    ///
299    /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need
300    /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is
301    /// done on final building.
302    pub fn with_custom<NewCustom: Module>(
303        self,
304        custom: NewCustom,
305    ) -> AppBuilder<BankT, ApiT, StorageT, NewCustom, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
306    {
307        let AppBuilder {
308            wasm,
309            bank,
310            api,
311            storage,
312            block,
313            staking,
314            distribution,
315            ibc,
316            gov,
317            stargate,
318            ..
319        } = self;
320
321        AppBuilder {
322            api,
323            block,
324            storage,
325            bank,
326            wasm,
327            custom,
328            staking,
329            distribution,
330            ibc,
331            gov,
332            stargate,
333        }
334    }
335
336    /// Overwrites the default staking interface.
337    pub fn with_staking<NewStaking: Staking>(
338        self,
339        staking: NewStaking,
340    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, NewStaking, DistrT, IbcT, GovT, StargateT>
341    {
342        let AppBuilder {
343            wasm,
344            api,
345            storage,
346            custom,
347            block,
348            bank,
349            distribution,
350            ibc,
351            gov,
352            stargate,
353            ..
354        } = self;
355
356        AppBuilder {
357            api,
358            block,
359            storage,
360            bank,
361            wasm,
362            custom,
363            staking,
364            distribution,
365            ibc,
366            gov,
367            stargate,
368        }
369    }
370
371    /// Overwrites the default distribution interface.
372    pub fn with_distribution<NewDistribution: Distribution>(
373        self,
374        distribution: NewDistribution,
375    ) -> AppBuilder<
376        BankT,
377        ApiT,
378        StorageT,
379        CustomT,
380        WasmT,
381        StakingT,
382        NewDistribution,
383        IbcT,
384        GovT,
385        StargateT,
386    > {
387        let AppBuilder {
388            wasm,
389            api,
390            storage,
391            custom,
392            block,
393            staking,
394            bank,
395            ibc,
396            gov,
397            stargate,
398            ..
399        } = self;
400
401        AppBuilder {
402            api,
403            block,
404            storage,
405            bank,
406            wasm,
407            custom,
408            staking,
409            distribution,
410            ibc,
411            gov,
412            stargate,
413        }
414    }
415
416    /// Overwrites the default ibc interface.
417    ///
418    /// If you wish to simply ignore/drop all returned IBC Messages,
419    /// you can use the `IbcAcceptingModule` type:
420    /// ```text
421    /// builder.with_ibc(IbcAcceptingModule::new())
422    /// ```
423    pub fn with_ibc<NewIbc: Ibc>(
424        self,
425        ibc: NewIbc,
426    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, NewIbc, GovT, StargateT>
427    {
428        let AppBuilder {
429            wasm,
430            api,
431            storage,
432            custom,
433            block,
434            staking,
435            bank,
436            distribution,
437            gov,
438            stargate,
439            ..
440        } = self;
441
442        AppBuilder {
443            api,
444            block,
445            storage,
446            bank,
447            wasm,
448            custom,
449            staking,
450            stargate,
451            distribution,
452            ibc,
453            gov,
454        }
455    }
456
457    /// Overwrites the default gov interface.
458    pub fn with_gov<NewGov: Gov>(
459        self,
460        gov: NewGov,
461    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, NewGov, StargateT>
462    {
463        let AppBuilder {
464            wasm,
465            api,
466            storage,
467            custom,
468            block,
469            staking,
470            bank,
471            distribution,
472            ibc,
473            stargate,
474            ..
475        } = self;
476
477        AppBuilder {
478            api,
479            block,
480            storage,
481            bank,
482            wasm,
483            custom,
484            staking,
485            distribution,
486            ibc,
487            gov,
488            stargate,
489        }
490    }
491
492    /// Overwrites the default stargate interface.
493    pub fn with_stargate<NewStargate: Stargate>(
494        self,
495        stargate: NewStargate,
496    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, NewStargate>
497    {
498        let AppBuilder {
499            wasm,
500            api,
501            storage,
502            custom,
503            block,
504            staking,
505            bank,
506            distribution,
507            ibc,
508            gov,
509            ..
510        } = self;
511
512        AppBuilder {
513            api,
514            block,
515            storage,
516            bank,
517            wasm,
518            custom,
519            staking,
520            distribution,
521            ibc,
522            gov,
523            stargate,
524        }
525    }
526
527    /// Overwrites the initial block.
528    pub fn with_block(mut self, block: BlockInfo) -> Self {
529        self.block = block;
530        self
531    }
532
533    /// Builds the final [App] with initialization.
534    ///
535    /// At this point all component types have to be properly related to each other.
536    pub fn build<F>(
537        self,
538        init_fn: F,
539    ) -> App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>
540    where
541        BankT: Bank,
542        ApiT: Api,
543        StorageT: Storage,
544        CustomT: Module,
545        WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
546        StakingT: Staking,
547        DistrT: Distribution,
548        IbcT: Ibc,
549        GovT: Gov,
550        StargateT: Stargate,
551        F: FnOnce(
552            &mut Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT, StargateT>,
553            &ApiT,
554            &mut dyn Storage,
555        ),
556    {
557        // build the final application
558        let mut app = App {
559            router: Router {
560                wasm: self.wasm,
561                bank: self.bank,
562                custom: self.custom,
563                staking: self.staking,
564                distribution: self.distribution,
565                ibc: self.ibc,
566                gov: self.gov,
567                stargate: self.stargate,
568            },
569            api: self.api,
570            block: self.block,
571            storage: self.storage,
572        };
573        // execute initialization provided by the caller
574        app.init_modules(init_fn);
575        // return already initialized application
576        app
577    }
578}