From 07207f6749b8f5c66fa9571d6b5d9fb6587322f5 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 9 Oct 2024 00:09:07 +0300 Subject: [PATCH] unified syntax - ReturnsResultOrError + tests --- .../scenarios/interactor_trace.scen.json | 4 +- .../scenarios/st-adder.scen.json | 4 +- .../feature-tests/scenario-tester/src/lib.rs | 4 +- .../src/scenario_tester_proxy.rs | 3 +- .../tests/st_blackbox_raw_steps_test.rs | 2 +- .../scenario-tester/tests/st_blackbox_test.rs | 38 ++++++++ .../tests/st_blackbox_upgrade_test.rs | 2 +- .../scenario/src/facade/result_handlers.rs | 2 + .../result_handlers/returns_result_or_err.rs | 89 +++++++++++++++++++ .../scenario/model/transaction/tx_error.rs | 21 ----- 10 files changed, 142 insertions(+), 27 deletions(-) create mode 100644 framework/scenario/src/facade/result_handlers/returns_result_or_err.rs delete mode 100644 framework/scenario/src/scenario/model/transaction/tx_error.rs diff --git a/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json b/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json index 07fd7f68ca..b5d3ed5b15 100644 --- a/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json +++ b/contracts/feature-tests/scenario-tester/scenarios/interactor_trace.scen.json @@ -36,7 +36,9 @@ "gasLimit": "70,000,000" }, "expect": { - "out": [], + "out": [ + "str:init-result" + ], "status": "0" } }, diff --git a/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json b/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json index 94ba305ed2..c2e6570007 100644 --- a/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json +++ b/contracts/feature-tests/scenario-tester/scenarios/st-adder.scen.json @@ -32,7 +32,9 @@ "gasPrice": "0" }, "expect": { - "out": [], + "out": [ + "str:init-result" + ], "status": "", "logs": "*", "gas": "*", diff --git a/contracts/feature-tests/scenario-tester/src/lib.rs b/contracts/feature-tests/scenario-tester/src/lib.rs index 97c352adeb..d5d2fd37e4 100644 --- a/contracts/feature-tests/scenario-tester/src/lib.rs +++ b/contracts/feature-tests/scenario-tester/src/lib.rs @@ -12,9 +12,11 @@ pub trait ScenarioTester { #[storage_mapper("sum")] fn sum(&self) -> SingleValueMapper; + /// Return value for testing reasons. #[init] - fn init(&self, initial_value: BigUint) { + fn init(&self, initial_value: BigUint) -> &'static str { self.sum().set(initial_value); + "init-result" } #[upgrade] diff --git a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs index 66976893c2..f5aae69fed 100644 --- a/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs +++ b/contracts/feature-tests/scenario-tester/src/scenario_tester_proxy.rs @@ -43,12 +43,13 @@ where From: TxFrom, Gas: TxGas, { + /// Return value for testing reasons. pub fn init< Arg0: ProxyArg>, >( self, initial_value: Arg0, - ) -> TxTypedDeploy { + ) -> TxTypedDeploy { self.wrapped_tx .payment(NotPayable) .raw_deploy() diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs index 68ac9b8d39..adc3ffa34e 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_raw_steps_test.rs @@ -25,7 +25,7 @@ fn scenario_tester_blackbox_raw() { .from("address:owner") .code(scenario_tester_code) .argument("5") - .expect(TxExpect::ok().no_result()), + .expect(TxExpect::ok().result("str:init-result")), ) .sc_query( ScQueryStep::new() diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs index d3f78692e8..9686dbcc32 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -286,3 +286,41 @@ fn st_blackbox_tx_hash() { assert_eq!(tx_hash.as_array(), &[22u8; 32]); } + +#[test] +fn st_blackbox_returns_result_or_error() { + let mut world = world(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .balance(100) + .account(OTHER_ADDRESS) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + let (result, check_tx_hash) = world + .tx() + .from(OWNER_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .init(5u32) + .code(CODE_PATH) + .new_address(ST_ADDRESS) + .tx_hash([33u8; 32]) + .returns( + ReturnsResultOrError::new() + .returns(ReturnsNewAddress) + .returns(ReturnsResultAs::::new()) + .returns(ReturnsTxHash), + ) + .returns(ReturnsTxHash) + .run(); + + assert_eq!(check_tx_hash.as_array(), &[33u8; 32]); + let (new_address, out_value, also_check_tx_hash) = result.unwrap(); + assert_eq!(new_address, ST_ADDRESS.to_address()); + assert_eq!(out_value, "init-result"); + assert_eq!(also_check_tx_hash.as_array(), &[33u8; 32]); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs index 3242739239..2fd12feaec 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_upgrade_test.rs @@ -29,7 +29,7 @@ fn st_blackbox_upgrade() { .code(&st_code) .argument("5") .gas_limit("5,000,000") - .expect(TxExpect::ok().no_result()), + .expect(TxExpect::ok().result("str:init-result")), ) .sc_call( ScCallStep::new() diff --git a/framework/scenario/src/facade/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs index 88e90d0cd5..7a5f0e779b 100644 --- a/framework/scenario/src/facade/result_handlers.rs +++ b/framework/scenario/src/facade/result_handlers.rs @@ -6,6 +6,7 @@ mod returns_logs; mod returns_message; mod returns_new_bech32_address; mod returns_new_token_identifier; +mod returns_result_or_err; mod returns_status; mod returns_tx_hash; mod with_tx_raw_response; @@ -18,6 +19,7 @@ pub use returns_logs::ReturnsLogs; pub use returns_message::ReturnsMessage; pub use returns_new_bech32_address::ReturnsNewBech32Address; pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; +pub use returns_result_or_err::ReturnsResultOrError; pub use returns_status::ReturnsStatus; pub use returns_tx_hash::ReturnsTxHash; pub use with_tx_raw_response::WithRawTxResponse; diff --git a/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs b/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs new file mode 100644 index 0000000000..7e3f3c245d --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_result_or_err.rs @@ -0,0 +1,89 @@ +use std::marker::PhantomData; + +use multiversx_sc::{ + tuple_util::NestedTupleFlatten, + types::{ + OriginalResultMarker, RHList, RHListAppendRet, RHListExec, RHListItem, RHListItemExec, + TxEnv, + }, +}; + +use crate::scenario_model::{TxResponse, TxResponseStatus}; + +/// Indicates that a `Result` will be returned, either with the handled result, +/// according to the inner result handlers, or with an error in case of a failed transaction. +pub struct ReturnsResultOrError +where + Env: TxEnv, + Ok: RHList, +{ + _phantom_env: PhantomData, + _phantom_original: PhantomData, + pub ok_t: Ok, +} + +impl Default for ReturnsResultOrError> +where + Env: TxEnv, +{ + fn default() -> Self { + ReturnsResultOrError { + _phantom_env: PhantomData, + _phantom_original: PhantomData, + ok_t: OriginalResultMarker::new(), + } + } +} + +impl ReturnsResultOrError> +where + Env: TxEnv, +{ + pub fn new() -> Self { + ReturnsResultOrError::default() + } +} + +impl ReturnsResultOrError +where + Env: TxEnv, + Ok: RHListExec, +{ + pub fn returns(self, item: RH) -> ReturnsResultOrError + where + RH: RHListItem, + Ok: RHListAppendRet, + { + ReturnsResultOrError { + _phantom_env: PhantomData, + _phantom_original: PhantomData, + ok_t: self.ok_t.append_ret(item), + } + } +} + +impl RHListItem for ReturnsResultOrError +where + Env: TxEnv, + Ok: RHListExec, + Ok::ListReturns: NestedTupleFlatten, +{ + type Returns = Result<::Unpacked, TxResponseStatus>; +} + +impl RHListItemExec + for ReturnsResultOrError +where + Env: TxEnv, + Ok: RHListExec, + Ok::ListReturns: NestedTupleFlatten, +{ + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + if raw_result.tx_error.is_success() { + let tuple_result = self.ok_t.list_process_result(raw_result); + Ok(tuple_result.flatten_unpack()) + } else { + Err(raw_result.tx_error.clone()) + } + } +} diff --git a/framework/scenario/src/scenario/model/transaction/tx_error.rs b/framework/scenario/src/scenario/model/transaction/tx_error.rs deleted file mode 100644 index d0a2b5a3e4..0000000000 --- a/framework/scenario/src/scenario/model/transaction/tx_error.rs +++ /dev/null @@ -1,21 +0,0 @@ -#[derive(Debug, Default, Clone)] -pub struct TxResponseStatus { - pub status: u64, - pub message: String, -} - -impl TxResponseStatus { - pub fn is_success(&self) -> bool { - self.status == 0 - } -} - -impl std::fmt::Display for TxResponseStatus { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.is_success() { - write!(f, "transaction successful") - } else { - write!(f, "transaction error: {}", self.message) - } - } -}