@@ -392,17 +392,110 @@ fn validate_length(bytes: &[u8]) -> StdResult<()> {
392392/// // `env3` is one block and 5.5 seconds later
393393/// ```
394394pub fn mock_env ( ) -> Env {
395- let contract_addr = MockApi :: default ( ) . addr_make ( "cosmos2contract" ) ;
396- Env {
397- block : BlockInfo {
398- height : 12_345 ,
399- time : Timestamp :: from_nanos ( 1_571_797_419_879_305_533 ) ,
400- chain_id : "cosmos-testnet-14002" . to_string ( ) ,
401- } ,
402- transaction : Some ( TransactionInfo { index : 3 } ) ,
403- contract : ContractInfo {
404- address : contract_addr,
405- } ,
395+ let mut envs = Envs :: new ( BECH32_PREFIX ) ;
396+ envs. make ( )
397+ }
398+
399+ /// A factory type that stores chain information such as bech32 prefix and can make mock `Env`s from there.
400+ ///
401+ /// It increments height for each mock call and block time by 5 seconds but is otherwise dumb.
402+ ///
403+ /// In contrast to using `mock_env`, the bech32 prefix must always be specified.
404+ ///
405+ /// ## Examples
406+ ///
407+ /// Typical usage
408+ ///
409+ /// ```
410+ /// # use cosmwasm_std::Timestamp;
411+ /// use cosmwasm_std::testing::Envs;
412+ ///
413+ /// let mut envs = Envs::new("food");
414+ ///
415+ /// let env = envs.make();
416+ /// assert_eq!(env.contract.address.as_str(), "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj");
417+ /// assert_eq!(env.block.height, 12_345);
418+ /// assert_eq!(env.block.time, Timestamp::from_nanos(1_571_797_419_879_305_533));
419+ ///
420+ /// let env = envs.make();
421+ /// assert_eq!(env.contract.address.as_str(), "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj");
422+ /// assert_eq!(env.block.height, 12_346);
423+ /// assert_eq!(env.block.time, Timestamp::from_nanos(1_571_797_424_879_305_533));
424+ ///
425+ /// let env = envs.make();
426+ /// assert_eq!(env.contract.address.as_str(), "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj");
427+ /// assert_eq!(env.block.height, 12_347);
428+ /// assert_eq!(env.block.time, Timestamp::from_nanos(1_571_797_429_879_305_533));
429+ /// ```
430+ ///
431+ /// Or use with iterator
432+ ///
433+ /// ```
434+ /// # use cosmwasm_std::Timestamp;
435+ /// use cosmwasm_std::testing::Envs;
436+ ///
437+ /// let mut envs = Envs::new("food");
438+ ///
439+ /// for (index, env) in envs.take(100).enumerate() {
440+ /// assert_eq!(env.contract.address.as_str(), "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj");
441+ /// assert_eq!(env.block.height, 12_345 + index as u64);
442+ /// assert_eq!(env.block.time, Timestamp::from_nanos(1_571_797_419_879_305_533).plus_seconds((index*5) as u64));
443+ /// }
444+ /// ```
445+ pub struct Envs {
446+ contract_address : Addr ,
447+ last_height : u64 ,
448+ last_time : Timestamp ,
449+ envs_produced : u64 ,
450+ }
451+
452+ impl Envs {
453+ pub fn new (
454+ bech32_prefix : & ' static str , /* static due to MockApi's Copy requirement. No better idea for now. */
455+ ) -> Self {
456+ let api = MockApi :: default ( ) . with_prefix ( bech32_prefix) ;
457+ Envs {
458+ // Default values here for compatibility with old `mock_env` function. They could be changed to anything else if there is a good reason.
459+ contract_address : api. addr_make ( "cosmos2contract" ) ,
460+ last_height : 12_344 ,
461+ last_time : Timestamp :: from_nanos ( 1_571_797_419_879_305_533 ) . minus_seconds ( 5 ) ,
462+ envs_produced : 0 ,
463+ }
464+ }
465+
466+ pub fn make ( & mut self ) -> Env {
467+ let height = self . last_height + 1 ;
468+ let time = self . last_time . plus_seconds ( 5 ) ;
469+
470+ self . last_height = height;
471+ self . last_time = time;
472+ self . envs_produced += 1 ;
473+
474+ Env {
475+ block : BlockInfo {
476+ height,
477+ time,
478+ chain_id : "cosmos-testnet-14002" . to_string ( ) ,
479+ } ,
480+ transaction : Some ( TransactionInfo { index : 3 } ) ,
481+ contract : ContractInfo {
482+ address : self . contract_address . clone ( ) ,
483+ } ,
484+ }
485+ }
486+ }
487+
488+ // The iterator implementation can produce 1 million envs and then stops for no good reason.
489+ impl Iterator for Envs {
490+ type Item = Env ;
491+
492+ fn next ( & mut self ) -> Option < Self :: Item > {
493+ if self . envs_produced < 1_000_000 {
494+ let item = self . make ( ) ;
495+ Some ( item)
496+ } else {
497+ None
498+ }
406499 }
407500}
408501
@@ -1272,6 +1365,71 @@ mod tests {
12721365 assert_eq ! ( contract_address, Addr :: unchecked( MOCK_CONTRACT_ADDR ) ) ;
12731366 }
12741367
1368+ #[ test]
1369+ fn envs_works ( ) {
1370+ let mut envs = Envs :: new ( "food" ) ;
1371+
1372+ let env = envs. make ( ) ;
1373+ assert_eq ! (
1374+ env. contract. address. as_str( ) ,
1375+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1376+ ) ;
1377+ assert_eq ! ( env. block. height, 12_345 ) ;
1378+ assert_eq ! (
1379+ env. block. time,
1380+ Timestamp :: from_nanos( 1_571_797_419_879_305_533 )
1381+ ) ;
1382+
1383+ let env = envs. make ( ) ;
1384+ assert_eq ! (
1385+ env. contract. address. as_str( ) ,
1386+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1387+ ) ;
1388+ assert_eq ! ( env. block. height, 12_346 ) ;
1389+ assert_eq ! (
1390+ env. block. time,
1391+ Timestamp :: from_nanos( 1_571_797_424_879_305_533 )
1392+ ) ;
1393+
1394+ let env = envs. make ( ) ;
1395+ assert_eq ! (
1396+ env. contract. address. as_str( ) ,
1397+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1398+ ) ;
1399+ assert_eq ! ( env. block. height, 12_347 ) ;
1400+ assert_eq ! (
1401+ env. block. time,
1402+ Timestamp :: from_nanos( 1_571_797_429_879_305_533 )
1403+ ) ;
1404+ }
1405+
1406+ #[ test]
1407+ fn envs_implements_iteratorworks ( ) {
1408+ let envs = Envs :: new ( "food" ) ;
1409+
1410+ let result: Vec < _ > = envs. into_iter ( ) . take ( 5 ) . collect ( ) ;
1411+
1412+ assert_eq ! (
1413+ result[ 0 ] . contract. address. as_str( ) ,
1414+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1415+ ) ;
1416+ assert_eq ! ( result[ 0 ] . block. height, 12_345 ) ;
1417+ assert_eq ! (
1418+ result[ 0 ] . block. time,
1419+ Timestamp :: from_nanos( 1_571_797_419_879_305_533 )
1420+ ) ;
1421+
1422+ assert_eq ! (
1423+ result[ 4 ] . contract. address. as_str( ) ,
1424+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1425+ ) ;
1426+ assert_eq ! ( result[ 4 ] . block. height, 12_349 ) ;
1427+ assert_eq ! (
1428+ result[ 4 ] . block. time,
1429+ Timestamp :: from_nanos( 1_571_797_439_879_305_533 )
1430+ ) ;
1431+ }
1432+
12751433 #[ test]
12761434 fn addr_validate_works ( ) {
12771435 // default prefix is 'cosmwasm'
0 commit comments