@@ -390,17 +390,110 @@ fn validate_length(bytes: &[u8]) -> StdResult<()> {
390
390
/// // `env3` is one block and 5.5 seconds later
391
391
/// ```
392
392
pub 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
+ }
404
497
}
405
498
}
406
499
@@ -1295,6 +1388,71 @@ mod tests {
1295
1388
)
1296
1389
}
1297
1390
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
+
1298
1456
#[ test]
1299
1457
fn addr_validate_works ( ) {
1300
1458
// default prefix is 'cosmwasm'
0 commit comments