thruput_native_exec/transaction_builder.rs
1use crate::frame_result::FrameResult;
2use crate::mock_transaction_handler::{
3 MockTransactionConfig, MockTransactionHandler,
4};
5use crate::test_environment::TestEnvironmentHandle;
6use crate::transact_result::TransactResult;
7use thruput_xdr::auth_claim::AuthClaim;
8
9/// Builder for configuring a mocked transaction before executing it.
10///
11/// Obtain one from [`TestEnvironment::transaction`](crate::test_environment::TestEnvironment::transaction),
12/// chain `with_*` methods to configure it, then finish with
13/// [`transact`](Self::transact), [`transact_manual`](Self::transact_manual),
14/// or [`build`](Self::build):
15///
16/// ```ignore
17/// env.transaction()
18/// .with_auth_claim(my_claim)
19/// .transact(|tx| tx.call(&addr).run(|| { /* ... */ }));
20/// ```
21///
22/// `env.transact(f)` and `env.transact_manual(f)` are shorthand for
23/// `env.transaction().transact(f)` / `.transact_manual(f)` with the default
24/// configuration.
25#[must_use = "a TransactionBuilder does nothing until `transact`, `transact_manual`, or `build` is called"]
26pub struct TransactionBuilder {
27 env: TestEnvironmentHandle,
28 config: MockTransactionConfig,
29}
30
31impl TransactionBuilder {
32 /// Start a builder with the default [`MockTransactionConfig`].
33 pub fn new(env: TestEnvironmentHandle) -> Self {
34 Self {
35 env,
36 config: MockTransactionConfig::default(),
37 }
38 }
39
40 /// Attach `auth_claim` to the mocked transaction instead of the default
41 /// source-address claim, controlling the auth-claim the contract under
42 /// test observes (e.g. via `get_auth_claim`).
43 pub fn with_auth_claim(mut self, auth_claim: AuthClaim) -> Self {
44 self.config.auth_claim = auth_claim;
45 self
46 }
47
48 /// Create the configured [`MockTransactionHandler`] for manual
49 /// orchestration. Prefer [`transact`](Self::transact) or
50 /// [`transact_manual`](Self::transact_manual) unless you need the handler
51 /// directly.
52 pub fn build(self) -> MockTransactionHandler {
53 MockTransactionHandler::new_with_config(self.env, self.config)
54 }
55
56 /// Execute a transaction with auto-commit. See
57 /// [`TestEnvironment::transact`](crate::test_environment::TestEnvironment::transact).
58 #[must_use]
59 pub fn transact(
60 self,
61 f: impl FnOnce(&mut MockTransactionHandler) -> FrameResult,
62 ) -> TransactResult {
63 let mut tx = self.build();
64 let frame_result = f(&mut tx);
65 let exec_result = tx.try_commit_transaction().exec_result();
66 TransactResult::new(frame_result, exec_result)
67 }
68
69 /// Execute a transaction with manual commit/abort control. See
70 /// [`TestEnvironment::transact_manual`](crate::test_environment::TestEnvironment::transact_manual).
71 ///
72 /// The closure must call `tx.try_commit_transaction()` or
73 /// `tx.abort_transaction()` before returning; forgetting panics here
74 /// (a dropped handler would abort silently).
75 pub fn transact_manual<R>(
76 self,
77 f: impl FnOnce(&mut MockTransactionHandler) -> R,
78 ) -> R {
79 let mut tx = self.build();
80 let out = f(&mut tx);
81 assert!(
82 !tx.is_running(),
83 "transact_manual closure returned without finishing the \
84 transaction: call tx.try_commit_transaction() or \
85 tx.abort_transaction() before returning"
86 );
87 out
88 }
89}