diff --git a/soroban-sdk/src/env.rs b/soroban-sdk/src/env.rs index 9e108bed0..de0176444 100644 --- a/soroban-sdk/src/env.rs +++ b/soroban-sdk/src/env.rs @@ -235,18 +235,38 @@ impl Default for Env { #[cfg(any(test, feature = "testutils"))] fn default() -> Self { - Self::default_with_testutils() + Self::new_with_config(EnvTestConfig::default()) } } #[cfg(any(test, feature = "testutils"))] #[derive(Clone, Default)] struct EnvTestState { + config: EnvTestConfig, generators: Rc>, auth_snapshot: Rc>, snapshot: Option>, } +/// Config for changing the default behavior of the Env when used in tests. +#[cfg(any(test, feature = "testutils"))] +#[derive(Clone)] +pub struct EnvTestConfig { + /// Capture a test snapshot when the Env is dropped, causing a test snapshot + /// JSON file to be written to disk when the Env is no longer referenced. + /// Defaults to true. + pub capture_snapshot_at_drop: bool, +} + +#[cfg(any(test, feature = "testutils"))] +impl Default for EnvTestConfig { + fn default() -> Self { + Self { + capture_snapshot_at_drop: true, + } + } +} + impl Env { /// Panic with the given error. /// @@ -457,7 +477,7 @@ impl Env { f((*self.test_state.generators).borrow_mut()) } - fn default_with_testutils() -> Env { + pub fn new_with_config(config: EnvTestConfig) -> Env { struct EmptySnapshotSource(); impl internal::storage::SnapshotSource for EmptySnapshotSource { @@ -487,11 +507,12 @@ impl Env { max_entry_ttl: 6_312_000, }; - Env::new_for_testutils(rf, None, info, None) + Env::new_for_testutils(config, rf, None, info, None) } /// Used by multiple constructors to configure test environments consistently. fn new_for_testutils( + config: EnvTestConfig, recording_footprint: Rc, generators: Option>>, ledger_info: internal::LedgerInfo, @@ -531,6 +552,7 @@ impl Env { let env = Env { env_impl, test_state: EnvTestState { + config, generators: generators.unwrap_or_default(), snapshot, auth_snapshot, @@ -1219,6 +1241,7 @@ impl Env { /// Events, as an output source only, are not loaded into the Env. pub fn from_snapshot(s: Snapshot) -> Env { Env::new_for_testutils( + EnvTestConfig::default(), // TODO: Allow setting the config. Rc::new(s.ledger.clone()), Some(Rc::new(RefCell::new(s.generators))), s.ledger.ledger_info(), @@ -1263,6 +1286,7 @@ impl Env { /// The ledger info and state in the snapshot are loaded into the Env. pub fn from_ledger_snapshot(s: LedgerSnapshot) -> Env { Env::new_for_testutils( + EnvTestConfig::default(), // TODO: Allow setting the config. Rc::new(s.clone()), None, s.ledger_info(), @@ -1329,7 +1353,7 @@ impl Drop for Env { // snapshot at that point when no other references to the host exist, // because it is only when there are no other references that the host // is being dropped. - if self.env_impl.can_finish() { + if self.env_impl.can_finish() && self.test_state.config.capture_snapshot_at_drop { self.to_test_snapshot_file(); } } diff --git a/soroban-sdk/src/lib.rs b/soroban-sdk/src/lib.rs index 458805b15..36a122d09 100644 --- a/soroban-sdk/src/lib.rs +++ b/soroban-sdk/src/lib.rs @@ -725,9 +725,8 @@ mod env; mod address; mod symbol; -pub use env::ConversionError; +pub use env::{ConversionError, Env}; -pub use env::Env; /// Raw value of the Soroban smart contract platform that types can be converted /// to and from for storing, or passing between contracts. /// diff --git a/soroban-sdk/src/tests/env.rs b/soroban-sdk/src/tests/env.rs index c570d4b67..73b64cb14 100644 --- a/soroban-sdk/src/tests/env.rs +++ b/soroban-sdk/src/tests/env.rs @@ -1,5 +1,6 @@ use crate::{ self as soroban_sdk, contract, contractimpl, + env::EnvTestConfig, testutils::{Address as _, Logs as _}, Address, Env, Error, }; @@ -147,3 +148,30 @@ fn test_snapshot_file() { let _ = std::fs::remove_file(&p1); let _ = std::fs::remove_file(&p2); } + +/// Test that the test snapshot file is not written when disabled. +#[test] +fn test_snapshot_file_disabled() { + let p = std::path::Path::new("test_snapshots") + .join("tests") + .join("env") + .join("test_snapshot_file_disabled"); + let p1 = p.with_extension("1.json"); + assert!(!p1.exists()); + let p2 = p.with_extension("2.json"); + assert!(!p2.exists()); + { + let e1 = Env::default(); + let _ = e1.register_contract(None, Contract); + let e2 = Env::new_with_config(EnvTestConfig { + capture_snapshot_at_drop: false, + }); + let _ = e2.register_contract(None, Contract); + assert!(!p1.exists()); + assert!(!p2.exists()); + } + assert!(p1.exists()); + assert!(!p2.exists()); + let _ = std::fs::remove_file(&p1); + let _ = std::fs::remove_file(&p2); +} diff --git a/soroban-sdk/src/testutils.rs b/soroban-sdk/src/testutils.rs index 64541f16f..0b593e32f 100644 --- a/soroban-sdk/src/testutils.rs +++ b/soroban-sdk/src/testutils.rs @@ -18,6 +18,8 @@ pub mod storage; use crate::{xdr, Env, Val, Vec}; use soroban_ledger_snapshot::LedgerSnapshot; +pub use crate::env::EnvTestConfig; + #[derive(Default, Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "snake_case")] pub struct Snapshot {