Skip to content

Commit

Permalink
refactor(gtest): introduce state_args macro for `read_state_using_w…
Browse files Browse the repository at this point in the history
…asm`
  • Loading branch information
mertwole authored Sep 4, 2023
1 parent ae511ce commit 807472a
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 13 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 101 additions & 8 deletions examples/new-meta/tests/read_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use demo_new_meta::{
MessageInitIn, Person, Wallet, META_EXPORTS_V1, META_EXPORTS_V2, META_WASM_V1, META_WASM_V2,
};
use gstd::Encode;
use gtest::{Program, System};
use gtest::{state_args, state_args_encoded, Program, System};

#[test]
fn read_state_bytes_returns_full_state() {
Expand All @@ -22,11 +22,11 @@ fn read_state_bytes_returns_full_state() {
fn read_state_bytes_with_wasm_func_returns_transformed_state() {
let system = System::new();
let program = initialize_current_program(&system);
const FIRST_WALLET_FUNC_NAME: &str = "first_wallet";
assert!(META_EXPORTS_V1.contains(&FIRST_WALLET_FUNC_NAME));
const FUNC_NAME: &str = "first_wallet";
assert!(META_EXPORTS_V1.contains(&FUNC_NAME));

let actual_state = program
.read_state_bytes_using_wasm(FIRST_WALLET_FUNC_NAME, META_WASM_V1.to_vec(), None)
.read_state_bytes_using_wasm(FUNC_NAME, META_WASM_V1.to_vec(), state_args_encoded!())
.expect("Unable to read program state");

let expected_state = Wallet::test_sequence().first().encode();
Expand All @@ -38,18 +38,18 @@ fn read_state_bytes_with_wasm_func_returns_transformed_state() {
fn read_state_bytes_with_parameterized_wasm_func_returns_transformed_state() {
let system = System::new();
let program = initialize_current_program(&system);
const WALLET_BY_PERSON_FUNC_NAME: &str = "wallet_by_person";
assert!(META_EXPORTS_V2.contains(&WALLET_BY_PERSON_FUNC_NAME));
const FUNC_NAME: &str = "wallet_by_person";
assert!(META_EXPORTS_V2.contains(&FUNC_NAME));
let other_person = Person {
surname: "OtherSurname".into(),
name: "OtherName".into(),
};

let actual_state = program
.read_state_bytes_using_wasm(
WALLET_BY_PERSON_FUNC_NAME,
FUNC_NAME,
META_WASM_V2.to_vec(),
Some(other_person.encode()),
state_args_encoded!(&other_person),
)
.expect("Unable to read program state");

Expand All @@ -61,6 +61,32 @@ fn read_state_bytes_with_parameterized_wasm_func_returns_transformed_state() {
assert_eq!(expected_state, actual_state);
}

#[test]
fn read_state_bytes_with_two_args_wasm_func_returns_transformed_state() {
let system = System::new();
let program = initialize_current_program(&system);
const FUNC_NAME: &str = "wallet_by_name_and_surname";
assert!(META_EXPORTS_V2.contains(&FUNC_NAME));

let name = "OtherName".to_string();
let surname = "OtherSurname".to_string();

let actual_state = program
.read_state_bytes_using_wasm(
FUNC_NAME,
META_WASM_V2.to_vec(),
state_args_encoded!(name.clone(), surname.clone()),
)
.expect("Unable to read program state");

let expected_state = Wallet::test_sequence()
.into_iter()
.find(|wallet| wallet.person.name == name && wallet.person.surname == surname)
.encode();

assert_eq!(expected_state, actual_state);
}

#[test]
fn read_state_returns_full_state() {
let system = System::new();
Expand All @@ -73,6 +99,73 @@ fn read_state_returns_full_state() {
assert_eq!(actual_state, expected_state);
}

#[test]
fn read_state_with_wasm_func_returns_transformed_state() {
let system = System::new();
let program = initialize_current_program(&system);
const FUNC_NAME: &str = "first_wallet";
assert!(META_EXPORTS_V1.contains(&FUNC_NAME));

let actual_state = program
.read_state_using_wasm(FUNC_NAME, META_WASM_V1.to_vec(), state_args!())
.expect("Unable to read program state");

let expected_state = Wallet::test_sequence().first().cloned();

assert_eq!(expected_state, actual_state);
}

#[test]
fn read_state_with_parameterized_wasm_func_returns_transformed_state() {
let system = System::new();
let program = initialize_current_program(&system);
const FUNC_NAME: &str = "wallet_by_person";
assert!(META_EXPORTS_V2.contains(&FUNC_NAME));
let other_person = Person {
surname: "OtherSurname".into(),
name: "OtherName".into(),
};

let actual_state = program
.read_state_using_wasm(
FUNC_NAME,
META_WASM_V2.to_vec(),
state_args!(other_person.clone()),
)
.expect("Unable to read program state");

let expected_state = Wallet::test_sequence()
.into_iter()
.find(|wallet| wallet.person == other_person);

assert_eq!(expected_state, actual_state);
}

#[test]
fn read_state_with_two_args_wasm_func_returns_transformed_state() {
let system = System::new();
let program = initialize_current_program(&system);
const FUNC_NAME: &str = "wallet_by_name_and_surname";
assert!(META_EXPORTS_V2.contains(&FUNC_NAME));

let name = "OtherName".to_string();
let surname = "OtherSurname".to_string();

let actual_state = program
.read_state_using_wasm(
FUNC_NAME,
META_WASM_V2.to_vec(),
state_args!(name.clone(), surname.clone()),
)
.expect("Unable to read program state");

let expected_state = Wallet::test_sequence()
.into_iter()
.find(|wallet| wallet.person.name == name && wallet.person.surname == surname);

assert_eq!(expected_state, actual_state);
}

fn initialize_current_program(system: &System) -> Program {
const SOME_USER_ID: u64 = 3;
let program = Program::current(system);
Expand Down
1 change: 1 addition & 0 deletions gtest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ demo-custom.workspace = true
demo-piggy-bank.workspace = true
demo-ping.workspace = true
demo-futures-unordered.workspace = true
demo-meta-io.workspace = true
1 change: 1 addition & 0 deletions gtest/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod program;
mod system;

pub use crate::log::{CoreLog, Log, RunResult};
pub use codec;
pub use error::{Result, TestError};
pub use program::{calculate_program_id, Gas, Program, WasmProgram};
pub use system::System;
Expand Down
5 changes: 2 additions & 3 deletions gtest/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ impl ExtManager {
program_id: &ProgramId,
fn_name: &str,
wasm: Vec<u8>,
argument: Option<Vec<u8>>,
args: Option<Vec<u8>>,
) -> Result<Vec<u8>> {
let mapping_code =
Code::new_raw(wasm, 1, None, true, false).map_err(|_| TestError::Instrumentation)?;
Expand All @@ -480,8 +480,7 @@ impl ExtManager {
.into_parts()
.0;

// The `metawasm` macro knows how to decode this as a tuple
let mut mapping_code_payload = argument.unwrap_or_default();
let mut mapping_code_payload = args.unwrap_or_default();
mapping_code_payload.append(&mut self.read_state_bytes(program_id)?);

core_processor::informational::execute_for_reply::<SandboxEnvironment<Ext, _>, _>(
Expand Down
121 changes: 119 additions & 2 deletions gtest/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,38 @@ impl From<&str> for ProgramIdWrapper {
}
}

#[macro_export]
macro_rules! state_args {
() => {
Option::<()>::None
};
($single:expr) => {
Some($single)
};
($($multiple:expr),*) => {
Some(($($multiple,)*))
};
}

#[macro_export]
macro_rules! state_args_encoded {
() => {
Option::<Vec<u8>>::None
};
($single:expr) => {
{
use $crate::codec::Encode;
Some(($single).encode())
}
};
($($multiple:expr),*) => {
{
use $crate::codec::Encode;
Some((($($multiple,)*)).encode())
}
};
}

pub struct Program<'a> {
pub(crate) manager: &'a RefCell<ExtManager>,
pub(crate) id: ProgramId,
Expand Down Expand Up @@ -421,15 +453,58 @@ impl<'a> Program<'a> {
/// Reads the program’s transformed state as a byte vector. The transformed
/// state is a result of applying the `fn_name` function from the `wasm`
/// binary with the optional `argument`.
///
/// # Usage
/// You can pass arguments as `Option<(arg1, arg2, ...).encode()>` or by
/// using [`state_args_encoded`] macro.
///
/// # Examples
///
/// ```
/// # use gtest::{state_args_encoded, Program, System, WasmProgram, Result};
/// # use codec::Encode;
/// # fn doctest() -> Result<()> {
/// # #[derive(Debug)]
/// # struct MockWasm {}
/// #
/// # impl WasmProgram for MockWasm {
/// # fn init(&mut self, _payload: Vec<u8>) -> Result<Option<Vec<u8>>, &'static str> { unimplemented!() }
/// # fn handle(&mut self, _payload: Vec<u8>) -> Result<Option<Vec<u8>>, &'static str> { unimplemented!() }
/// # fn handle_reply(&mut self, _payload: Vec<u8>) -> Result<(), &'static str> {unimplemented!() }
/// # fn handle_signal(&mut self, _payload: Vec<u8>) -> Result<(), &'static str> { unimplemented!() }
/// # fn state(&mut self) -> Result<Vec<u8>, &'static str> { unimplemented!() }
/// # }
/// # let system = System::new();
/// # let program = Program::mock(&system, MockWasm { });
/// # let ARG_1 = 0u8;
/// # let ARG_2 = 0u8;
/// //Read state bytes with no arguments passed to wasm.
/// # let WASM = vec![];
/// let _ = program.read_state_bytes_using_wasm("fn_name", WASM, Option::<Vec<u8>>::None)?;
/// # let WASM = vec![];
/// let _ = program.read_state_bytes_using_wasm("fn_name", WASM, state_args_encoded!())?;
/// // Read state bytes with one argument passed to wasm.
/// # let WASM = vec![];
/// let _ = program.read_state_bytes_using_wasm("fn_name", WASM, Some(ARG_1.encode()))?;
/// # let WASM = vec![];
/// let _ = program.read_state_bytes_using_wasm("fn_name", WASM, state_args_encoded!(ARG_1))?;
/// // Read state bytes with multiple arguments passed to wasm.
/// # let WASM = vec![];
/// let _ = program.read_state_bytes_using_wasm("fn_name", WASM, Some((ARG_1, ARG_2).encode()))?;
/// # let WASM = vec![];
/// let _ = program.read_state_bytes_using_wasm("fn_name", WASM, state_args_encoded!(ARG_1, ARG_2))?;
/// # Ok(())
/// # }
/// ```
pub fn read_state_bytes_using_wasm(
&self,
fn_name: &str,
wasm: Vec<u8>,
argument: Option<Vec<u8>>,
args: Option<Vec<u8>>,
) -> Result<Vec<u8>> {
self.manager
.borrow_mut()
.read_state_bytes_using_wasm(&self.id, fn_name, wasm, argument)
.read_state_bytes_using_wasm(&self.id, fn_name, wasm, args)
}

/// Reads and decodes the program's state .
Expand All @@ -441,6 +516,48 @@ impl<'a> Program<'a> {
/// Reads and decodes the program’s transformed state. The transformed state
/// is a result of applying the `fn_name` function from the `wasm`
/// binary with the optional `argument`.
///
/// # Usage
/// You can pass arguments as `Option<(arg1, arg2, ...)>` or by
/// using [`state_args`] macro.
///
/// # Examples
///
/// ```
/// # use gtest::{state_args, Program, System, WasmProgram, Result};
/// # fn doctest() -> Result<()> {
/// # #[derive(Debug)]
/// # struct MockWasm {}
/// #
/// # impl WasmProgram for MockWasm {
/// # fn init(&mut self, _payload: Vec<u8>) -> Result<Option<Vec<u8>>, &'static str> { unimplemented!() }
/// # fn handle(&mut self, _payload: Vec<u8>) -> Result<Option<Vec<u8>>, &'static str> { unimplemented!() }
/// # fn handle_reply(&mut self, _payload: Vec<u8>) -> Result<(), &'static str> {unimplemented!() }
/// # fn handle_signal(&mut self, _payload: Vec<u8>) -> Result<(), &'static str> { unimplemented!() }
/// # fn state(&mut self) -> Result<Vec<u8>, &'static str> { unimplemented!() }
/// # }
/// # let system = System::new();
/// # let program = Program::mock(&system, MockWasm { });
/// # let ARG_1 = 0u8;
/// # let ARG_2 = 0u8;
/// //Read state bytes with no arguments passed to wasm.
/// # let WASM = vec![];
/// let _ = program.read_state_using_wasm("fn_name", WASM, Option::<()>::None)?;
/// # let WASM = vec![];
/// let _ = program.read_state_using_wasm("fn_name", WASM, state_args!())?;
/// // Read state bytes with one argument passed to wasm.
/// # let WASM = vec![];
/// let _ = program.read_state_using_wasm("fn_name", WASM, Some(ARG_1))?;
/// # let WASM = vec![];
/// let _ = program.read_state_using_wasm("fn_name", WASM, state_args!(ARG_1))?;
/// // Read state bytes with multiple arguments passed to wasm.
/// # let WASM = vec![];
/// let _ = program.read_state_using_wasm("fn_name", WASM, Some((ARG_1, ARG_2)))?;
/// # let WASM = vec![];
/// let _ = program.read_state_using_wasm("fn_name", WASM, state_args!(ARG_1, ARG_2))?;
/// # Ok(())
/// # }
/// ```
pub fn read_state_using_wasm<E: Encode, D: Decode>(
&self,
fn_name: &str,
Expand Down

0 comments on commit 807472a

Please sign in to comment.