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