Skip to content

Commit

Permalink
docs(soroban-test): finish adding docs
Browse files Browse the repository at this point in the history
  • Loading branch information
chadoh committed Feb 27, 2023
1 parent 1a0b045 commit a9ff0c0
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
40 changes: 39 additions & 1 deletion cmd/crates/soroban-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub enum Error {
/// .args(["--fn", "some_fn"])
/// .assert()
/// .stderr("");
/// });
/// });
/// }
pub struct TestEnv {
pub temp_dir: TempDir,
Expand All @@ -47,26 +47,55 @@ impl Default for TestEnv {
}

impl TestEnv {
/// Initialize a TestEnv with default settings. Takes a closure to execute within this TestEnv.
///
/// For now, this is the primary interface to create and use a TestEnv. In the future, TestEnv
/// may provide an alternate, more customizable method of initialization.
///
/// # Example
///
/// In a test function:
///
/// TestEnv::with_default(|e| {
/// println!("{:#?}", e.new_cmd("version").ok());
/// });
pub fn with_default<F: FnOnce(&TestEnv)>(f: F) {
let test_env = TestEnv::default();
f(&test_env)
}

/// Initialize a TestEnv with default settings and return a Result with this TestEnv or an
/// error. You probably want `with_default` instead, which makes use of `new` internally.
pub fn new() -> Result<TestEnv, Error> {
TempDir::new()
.map_err(Error::TempDir)
.map(|temp_dir| TestEnv { temp_dir })
}

/// Start building a new `soroban` command, skipping the repetitive `soroban` starting word and
/// setting the current directory to the one for this TestEnv.
///
/// # Example
///
/// TestEnv::with_default(|e| {
/// println!("{:#?}", e.new_cmd("version").ok());
/// });
///
/// Note that you don't need `e.new_cmd("soroban").arg("version")`.
pub fn new_cmd(&self, name: &str) -> Command {
let mut this = Command::cargo_bin("soroban").unwrap_or_else(|_| Command::new("soroban"));
this.arg(name);
this.current_dir(&self.temp_dir);
this
}

/// Get the location of the temporary directory created by this TestEnv.
pub fn dir(&self) -> &TempDir {
&self.temp_dir
}

/// Generate new identity for testing. Names the identity `test`. Uses a hard-coded all-zero
/// seed.
pub fn gen_test_identity(&self) {
self.new_cmd("config")
.arg("identity")
Expand All @@ -78,6 +107,13 @@ impl TestEnv {
.success();
}

/// Return a public key of the identity named `test`, which needs to first be created with
/// `gen_test_identity`. The `test` identity is stored as a seed, which can be used to generate
/// multiple public keys. The specific key generated depends on the `hd_path` supplied.
/// Specifying the same `hd_path` will always generate the same key.
///
/// The phrase "HD path" comes from the larger world of crypto wallets:
/// https://www.ledger.com/academy/crypto/what-are-hierarchical-deterministic-hd-wallets
pub fn test_address(&self, hd_path: usize) -> String {
self.new_cmd("config")
.args("identity address test --hd-path".split(' '))
Expand All @@ -86,6 +122,8 @@ impl TestEnv {
.stdout_as_str()
}

/// Fork TestEnv, return a Result with the new TestEnv or an error. Might be useful to create
/// multiple tests that use the same setup.
pub fn fork(&self) -> Result<TestEnv, Error> {
let this = TestEnv::new()?;
self.save(&this.temp_dir)?;
Expand Down
35 changes: 35 additions & 0 deletions cmd/crates/soroban-test/src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,38 @@ pub enum Error {
Xdr(#[from] xdr::Error),
}

/// Easily include a built Wasm artifact from your project's `target` folder
///
/// # Example
///
/// If your workspace includes a member with name "my-contract" (that is, with `name =
/// "my-contract"` in its Cargo.toml), or if this is the name of your root project, then in your
/// test you can use:
///
/// use soroban_test::{TestEnv, Wasm};
/// const WASM: &Wasm = &Wasm::Release("my_contract");
///
/// #[test]
/// fn invoke_and_read() {
/// TestEnv::with_default(|e| {
/// let output = e.new_cmd("contract")
/// .arg("invoke")
/// .arg("--wasm")
/// .arg(&WASM.path())
/// .ok();
/// })
/// }
pub enum Wasm<'a> {
/// Takes a filename. Look inside `target/wasm32-unknown-unknown/release` for a Wasm file with
/// the given name.
Release(&'a str),

/// Takes a `profile` and a filename. Look inside `target/wasm32-unknown-unknown/{profile}` for
/// a given Wasm file with the given name.
///
/// # Example
///
/// const WASM: &Wasm = &Wasm::Custom("debug", "my_contract");
Custom(&'a str, &'a str),
}

Expand All @@ -26,6 +56,7 @@ fn find_target_dir() -> Option<PathBuf> {
}

impl Wasm<'_> {
/// The file path to the specified Wasm file
pub fn path(&self) -> PathBuf {
let path = find_target_dir().unwrap().join("wasm32-unknown-unknown");
let mut path = match self {
Expand All @@ -37,10 +68,14 @@ impl Wasm<'_> {
std::env::current_dir().unwrap().join(path)
}

/// The bytes of the specified Wasm file
pub fn bytes(&self) -> Vec<u8> {
fs::read(self.path()).unwrap()
}

/// The derived hash of the specified Wasm file which will be used to refer to a contract
/// "installed" in the Soroban blockchain (that is, to contract bytes that have been uploaded,
/// and which zero or more contract instances may refer to for their behavior).
pub fn hash(&self) -> Result<xdr::Hash, Error> {
let args_xdr = InstallContractCodeArgs {
code: self.bytes().try_into()?,
Expand Down

0 comments on commit a9ff0c0

Please sign in to comment.