@@ -392,17 +392,110 @@ fn validate_length(bytes: &[u8]) -> StdResult<()> {
392
392
/// // `env3` is one block and 5.5 seconds later
393
393
/// ```
394
394
pub 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
+ }
406
499
}
407
500
}
408
501
@@ -1285,6 +1378,71 @@ mod tests {
1285
1378
)
1286
1379
}
1287
1380
1381
+ #[ test]
1382
+ fn envs_works ( ) {
1383
+ let mut envs = Envs :: new ( "food" ) ;
1384
+
1385
+ let env = envs. make ( ) ;
1386
+ assert_eq ! (
1387
+ env. contract. address. as_str( ) ,
1388
+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1389
+ ) ;
1390
+ assert_eq ! ( env. block. height, 12_345 ) ;
1391
+ assert_eq ! (
1392
+ env. block. time,
1393
+ Timestamp :: from_nanos( 1_571_797_419_879_305_533 )
1394
+ ) ;
1395
+
1396
+ let env = envs. make ( ) ;
1397
+ assert_eq ! (
1398
+ env. contract. address. as_str( ) ,
1399
+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1400
+ ) ;
1401
+ assert_eq ! ( env. block. height, 12_346 ) ;
1402
+ assert_eq ! (
1403
+ env. block. time,
1404
+ Timestamp :: from_nanos( 1_571_797_424_879_305_533 )
1405
+ ) ;
1406
+
1407
+ let env = envs. make ( ) ;
1408
+ assert_eq ! (
1409
+ env. contract. address. as_str( ) ,
1410
+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1411
+ ) ;
1412
+ assert_eq ! ( env. block. height, 12_347 ) ;
1413
+ assert_eq ! (
1414
+ env. block. time,
1415
+ Timestamp :: from_nanos( 1_571_797_429_879_305_533 )
1416
+ ) ;
1417
+ }
1418
+
1419
+ #[ test]
1420
+ fn envs_implements_iteratorworks ( ) {
1421
+ let envs = Envs :: new ( "food" ) ;
1422
+
1423
+ let result: Vec < _ > = envs. into_iter ( ) . take ( 5 ) . collect ( ) ;
1424
+
1425
+ assert_eq ! (
1426
+ result[ 0 ] . contract. address. as_str( ) ,
1427
+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1428
+ ) ;
1429
+ assert_eq ! ( result[ 0 ] . block. height, 12_345 ) ;
1430
+ assert_eq ! (
1431
+ result[ 0 ] . block. time,
1432
+ Timestamp :: from_nanos( 1_571_797_419_879_305_533 )
1433
+ ) ;
1434
+
1435
+ assert_eq ! (
1436
+ result[ 4 ] . contract. address. as_str( ) ,
1437
+ "food1jpev2csrppg792t22rn8z8uew8h3sjcpglcd0qv9g8gj8ky922ts74yrjj"
1438
+ ) ;
1439
+ assert_eq ! ( result[ 4 ] . block. height, 12_349 ) ;
1440
+ assert_eq ! (
1441
+ result[ 4 ] . block. time,
1442
+ Timestamp :: from_nanos( 1_571_797_439_879_305_533 )
1443
+ ) ;
1444
+ }
1445
+
1288
1446
#[ test]
1289
1447
fn addr_validate_works ( ) {
1290
1448
// default prefix is 'cosmwasm'
0 commit comments