1#[cfg(not(target_arch = "wasm32"))]
2use crate::host::host_bindings_trait::{HostBindings, MockHostBindings};
3use std::cell::RefCell;
4
5#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
6pub struct MockGuard;
7
8#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
9impl Drop for MockGuard {
10 fn drop(&mut self) {
11 clear_mock_host_bindings();
12 }
13}
14
15#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
16pub fn setup_mock(mock: MockHostBindings) -> MockGuard {
17 set_mock_host_bindings(mock);
18 MockGuard
19}
20
21#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
23pub fn create_default_mock() -> MockHostBindings {
24 let mut mock = MockHostBindings::new();
25 apply_default_expectations(&mut mock);
26 mock
27}
28
29#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
38pub fn apply_default_expectations(mock: &mut MockHostBindings) {
39 mock.expect_get_ledger_sqn()
41 .returning(|_, out_buff_len| out_buff_len as i32);
42 mock.expect_get_parent_ledger_time()
43 .returning(|_, out_buff_len| out_buff_len as i32);
44 mock.expect_get_base_fee()
45 .returning(|_, out_buff_len| out_buff_len as i32);
46
47 mock.expect_get_parent_ledger_hash()
49 .returning(|_, out_buff_len| out_buff_len as i32);
50 mock.expect_amendment_enabled()
51 .returning(|_, amendment_len| amendment_len as i32);
52 mock.expect_cache_ledger_obj()
53 .returning(|_, keylet_len, _| keylet_len as i32);
54 mock.expect_get_tx_field()
55 .returning(|_, _, out_buff_len| out_buff_len as i32);
56 mock.expect_get_current_ledger_obj_field()
57 .returning(|_, _, out_buff_len| out_buff_len as i32);
58 mock.expect_get_ledger_obj_field()
59 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
60 mock.expect_get_tx_nested_field()
61 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
62 mock.expect_get_current_ledger_obj_nested_field()
63 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
64 mock.expect_get_ledger_obj_nested_field()
65 .returning(|_, _, _, _, out_buff_len| out_buff_len as i32);
66
67 mock.expect_get_tx_array_len().returning(|_| 0);
69 mock.expect_get_current_ledger_obj_array_len()
70 .returning(|_| 0);
71 mock.expect_get_ledger_obj_array_len().returning(|_, _| 0);
72 mock.expect_get_tx_nested_array_len().returning(|_, _| 0);
73 mock.expect_get_current_ledger_obj_nested_array_len()
75 .returning(|_, locator_len| locator_len as i32);
76 mock.expect_get_ledger_obj_nested_array_len()
77 .returning(|_, _, locator_len| locator_len as i32);
78
79 mock.expect_update_data()
81 .returning(|_, data_len| data_len as i32);
82 mock.expect_compute_sha512_half()
83 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
84 mock.expect_check_sig().returning(|_, _, _, _, _, _| 0);
85
86 mock.expect_account_keylet()
88 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
89 mock.expect_amm_keylet()
90 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
91 mock.expect_check_keylet()
92 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
93 mock.expect_credential_keylet()
94 .returning(|_, _, _, _, _, _, _, out_buff_len| out_buff_len as i32);
95 mock.expect_delegate_keylet()
96 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
97 mock.expect_deposit_preauth_keylet()
98 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
99 mock.expect_did_keylet()
100 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
101 mock.expect_escrow_keylet()
102 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
103 mock.expect_line_keylet()
104 .returning(|_, _, _, _, _, _, _, out_buff_len| out_buff_len as i32);
105 mock.expect_mpt_issuance_keylet()
106 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
107 mock.expect_mptoken_keylet()
108 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
109 mock.expect_nft_offer_keylet()
110 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
111 mock.expect_offer_keylet()
112 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
113 mock.expect_oracle_keylet()
114 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
115 mock.expect_paychan_keylet()
116 .returning(|_, _, _, _, _, _, _, out_buff_len| out_buff_len as i32);
117 mock.expect_permissioned_domain_keylet()
118 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
119 mock.expect_signers_keylet()
120 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
121 mock.expect_ticket_keylet()
122 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
123 mock.expect_vault_keylet()
124 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
125
126 mock.expect_get_nft()
128 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
129 mock.expect_get_nft_issuer()
130 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
131 mock.expect_get_nft_taxon()
132 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
133 mock.expect_get_nft_flags()
134 .returning(|_, nft_id_len| nft_id_len as i32);
135 mock.expect_get_nft_transfer_fee()
136 .returning(|_, nft_id_len| nft_id_len as i32);
137 mock.expect_get_nft_serial()
138 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
139
140 mock.expect_float_from_int()
142 .returning(|_, _, out_buff_len, _| out_buff_len as i32);
143 mock.expect_float_from_uint()
144 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
145 mock.expect_float_from_mant_exp()
146 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
147 mock.expect_float_from_stamount()
148 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
149 mock.expect_float_from_stnumber()
150 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
151 mock.expect_float_to_int()
152 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
153 mock.expect_float_to_mant_exp()
154 .returning(|_, _, _, _, _, _| 8);
155 mock.expect_float_compare().returning(|_, _, _, _| 0);
156 mock.expect_float_add()
157 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
158 mock.expect_float_subtract()
159 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
160 mock.expect_float_multiply()
161 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
162 mock.expect_float_divide()
163 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
164 mock.expect_float_pow()
165 .returning(|_, _, _, _, out_buff_len, _| out_buff_len as i32);
166 mock.expect_float_root()
167 .returning(|_, _, _, _, out_buff_len, _| out_buff_len as i32);
168
169 let sum_lengths = |len1: usize, len2: usize| -> i32 {
171 len1.saturating_add(len2).min(i32::MAX as usize) as i32
172 };
173
174 mock.expect_trace()
176 .returning(move |_, msg_len, _, data_len, _| sum_lengths(msg_len, data_len));
177 mock.expect_trace_num()
178 .returning(move |_, msg_len, _| sum_lengths(msg_len, 8));
179 mock.expect_trace_account()
180 .returning(move |_, msg_len, _, acc_len| sum_lengths(msg_len, acc_len));
181 mock.expect_trace_opaque_float()
182 .returning(move |_, msg_len, _, float_len| sum_lengths(msg_len, float_len));
183 mock.expect_trace_amount()
184 .returning(move |_, msg_len, _, amt_len| sum_lengths(msg_len, amt_len));
185}
186
187#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
189thread_local! {
190 static MOCK_STATE: RefCell<Option<MockHostBindings>> = RefCell::new(Some(create_default_mock()));
191}
192
193#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
195pub fn set_mock_host_bindings(mock: MockHostBindings) {
196 MOCK_STATE.with(|state| {
197 *state.borrow_mut() = Some(mock);
198 });
199}
200
201#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
202pub fn clear_mock_host_bindings() {
203 MOCK_STATE.with(|state| {
204 *state.borrow_mut() = None;
205 });
206}
207
208#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
209macro_rules! export_host_functions {
212 ($(
213 $(#[$attr:meta])*
214 fn $name:ident($($param:ident: $param_ty:ty),*) -> $ret:ty;
215 )*) => {
216 $(
217 #[allow(clippy::too_many_arguments)]
218 #[allow(clippy::missing_safety_doc)]
219 $(#[$attr])*
220 pub unsafe fn $name($($param: $param_ty),*) -> $ret {
221 MOCK_STATE.with(|state| {
222 let mock = state.borrow();
225 let mock_ref = mock.as_ref().expect("MockHostBindings not initialized");
226 unsafe { mock_ref.$name($($param),*) }
227 })
228 }
229 )*
230 };
231}
232
233export_host_functions! {
239 fn get_ledger_sqn(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
241 fn get_parent_ledger_time(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
242 fn get_parent_ledger_hash(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
243 fn get_base_fee(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
244 fn amendment_enabled(amendment_ptr: *const u8, amendment_len: usize) -> i32;
245 fn cache_ledger_obj(keylet_ptr: *const u8, keylet_len: usize, cache_num: i32) -> i32;
246 fn get_tx_field(field: i32, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
247 fn get_current_ledger_obj_field(field: i32, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
248 fn get_ledger_obj_field(cache_num: i32, field: i32, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
249 fn get_tx_nested_field(locator_ptr: *const u8, locator_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
250 fn get_current_ledger_obj_nested_field(locator_ptr: *const u8, locator_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
251 fn get_ledger_obj_nested_field(cache_num: i32, locator_ptr: *const u8, locator_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
252 fn get_tx_array_len(field: i32) -> i32;
253 fn get_current_ledger_obj_array_len(field: i32) -> i32;
254 fn get_ledger_obj_array_len(cache_num: i32, field: i32) -> i32;
255 fn get_tx_nested_array_len(locator_ptr: *const u8, locator_len: usize) -> i32;
256 fn get_current_ledger_obj_nested_array_len(locator_ptr: *const u8, locator_len: usize) -> i32;
257 fn get_ledger_obj_nested_array_len(cache_num: i32, locator_ptr: *const u8, locator_len: usize) -> i32;
258
259 fn update_data(data_ptr: *const u8, data_len: usize) -> i32;
261
262 fn compute_sha512_half(data_ptr: *const u8, data_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
264 fn check_sig(message_ptr: *const u8, message_len: usize, signature_ptr: *const u8, signature_len: usize, pubkey_ptr: *const u8, pubkey_len: usize) -> i32;
265 fn account_keylet(account_ptr: *const u8, account_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
266 fn amm_keylet(issue1_ptr: *const u8, issue1_len: usize, issue2_ptr: *const u8, issue2_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
267 fn check_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
268 fn credential_keylet(subject_ptr: *const u8, subject_len: usize, issuer_ptr: *const u8, issuer_len: usize, cred_type_ptr: *const u8, cred_type_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
269 fn delegate_keylet(account_ptr: *const u8, account_len: usize, authorize_ptr: *const u8, authorize_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
270 fn deposit_preauth_keylet(account_ptr: *const u8, account_len: usize, authorize_ptr: *const u8, authorize_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
271 fn did_keylet(account_ptr: *const u8, account_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
272 fn escrow_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
273 fn line_keylet(account1_ptr: *const u8, account1_len: usize, account2_ptr: *const u8, account2_len: usize, currency_ptr: *const u8, currency_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
274 fn mpt_issuance_keylet(issuer_ptr: *const u8, issuer_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
275 fn mptoken_keylet(mptid_ptr: *const u8, mptid_len: usize, holder_ptr: *const u8, holder_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
276 fn nft_offer_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
277 fn offer_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
278 fn oracle_keylet(account_ptr: *const u8, account_len: usize, document_id_ptr: *const u8, document_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
279 fn paychan_keylet(account_ptr: *const u8, account_len: usize, destination_ptr: *const u8, destination_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
280 fn permissioned_domain_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
281 fn signers_keylet(account_ptr: *const u8, account_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
282 fn ticket_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
283 fn vault_keylet(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
284
285 fn get_nft(account_ptr: *const u8, account_len: usize, nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
287 fn get_nft_issuer(nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
288 fn get_nft_taxon(nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
289 fn get_nft_flags(nft_id_ptr: *const u8, nft_id_len: usize) -> i32;
290 fn get_nft_transfer_fee(nft_id_ptr: *const u8, nft_id_len: usize) -> i32;
291 fn get_nft_serial(nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
292
293 fn float_from_int(in_int: i64, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
295 fn float_from_uint(in_uint_ptr: *const u8, in_uint_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
296 fn float_from_mant_exp(mantissa: i64, exponent: i32, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
297 fn float_from_stamount(in_buff: *const u8, in_buff_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
298 fn float_from_stnumber(in_buff: *const u8, in_buff_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
299 fn float_to_int(in_buff: *const u8, in_buff_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
300 fn float_to_mant_exp(in_buff: *const u8, in_buff_len: usize, mant_buff: *mut u8, mant_buff_len: usize, exp_buff: *mut u8, exp_buff_len: usize) -> i32;
301 fn float_compare(in_buff1: *const u8, in_buff1_len: usize, in_buff2: *const u8, in_buff2_len: usize) -> i32;
302 fn float_add(in_buff1: *const u8, in_buff1_len: usize, in_buff2: *const u8, in_buff2_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
303 fn float_subtract(in_buff1: *const u8, in_buff1_len: usize, in_buff2: *const u8, in_buff2_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
304 fn float_multiply(in_buff1: *const u8, in_buff1_len: usize, in_buff2: *const u8, in_buff2_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
305 fn float_divide(in_buff1: *const u8, in_buff1_len: usize, in_buff2: *const u8, in_buff2_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
306 fn float_pow(in_buff: *const u8, in_buff_len: usize, pow: i32, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
307 fn float_root(in_buff: *const u8, in_buff_len: usize, root: i32, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
308
309 fn trace(msg_read_ptr: *const u8, msg_read_len: usize, data_read_ptr: *const u8, data_read_len: usize, as_hex: i32) -> i32;
311 fn trace_num(msg_read_ptr: *const u8, msg_read_len: usize, number: i64) -> i32;
312 fn trace_account(msg_read_ptr: *const u8, msg_read_len: usize, account_ptr: *const u8, account_len: usize) -> i32;
313 fn trace_opaque_float(msg_read_ptr: *const u8, msg_read_len: usize, opaque_float_ptr: *const u8, opaque_float_len: usize) -> i32;
314 fn trace_amount(msg_read_ptr: *const u8, msg_read_len: usize, amount_ptr: *const u8, amount_len: usize) -> i32;
315
316}
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn test_ledger_functions_with_mock() {
324 let mut mock = MockHostBindings::new();
325
326 mock.expect_get_ledger_sqn()
328 .times(1)
329 .returning(|_, _| 12345);
330 mock.expect_get_parent_ledger_time()
331 .times(1)
332 .returning(|_, _| 1234567890);
333 mock.expect_get_base_fee().times(1).returning(|_, _| 10);
334
335 set_mock_host_bindings(mock);
337
338 let mut buffer = [0u8; 32];
340 unsafe {
341 assert_eq!(get_ledger_sqn(buffer.as_mut_ptr(), buffer.len()), 12345);
342 assert_eq!(
343 get_parent_ledger_time(buffer.as_mut_ptr(), buffer.len()),
344 1234567890
345 );
346 assert_eq!(get_base_fee(buffer.as_mut_ptr(), buffer.len()), 10);
347 }
348
349 clear_mock_host_bindings();
351 }
352
353 #[test]
354 fn test_buffer_operations_with_mock() {
355 let mut mock = MockHostBindings::new();
356
357 mock.expect_get_parent_ledger_hash()
359 .times(1)
360 .returning(|out_buff_ptr, out_buff_len| {
361 if out_buff_len >= 32 {
362 unsafe {
363 for i in 0..32 {
365 *out_buff_ptr.add(i) = (i * 2) as u8;
366 }
367 }
368 32 } else {
370 -1 }
372 });
373
374 let mut buffer = [0u8; 32];
376 unsafe {
377 let result = mock.get_parent_ledger_hash(buffer.as_mut_ptr(), buffer.len());
378 assert_eq!(result, 32);
379
380 for (i, _) in buffer.iter().enumerate() {
382 assert_eq!(buffer[i], (i * 2) as u8);
383 }
384 }
385 }
386
387 #[test]
388 fn test_trace_functions_with_mock() {
389 let mut mock = MockHostBindings::new();
390
391 mock.expect_trace().times(1).returning(
393 |_msg_ptr, msg_len, _data_ptr, data_len, _as_hex| (msg_len + data_len) as i32,
394 );
395
396 mock.expect_trace_num()
398 .times(1)
399 .returning(|_msg_ptr, msg_len, _number| msg_len as i32);
400
401 let message = b"Test message";
403 let data = b"Test data";
404
405 unsafe {
406 let result = mock.trace(
407 message.as_ptr(),
408 message.len(),
409 data.as_ptr(),
410 data.len(),
411 0,
412 );
413 assert_eq!(result, (message.len() + data.len()) as i32);
414
415 let result = mock.trace_num(message.as_ptr(), message.len(), 42);
416 assert_eq!(result, message.len() as i32);
417 }
418 }
419
420 #[test]
421 fn test_keylet_functions_with_mock() {
422 let mut mock = MockHostBindings::new();
423
424 mock.expect_account_keylet().times(1).returning(
426 |_account_ptr, _account_len, out_buff_ptr, out_buff_len| {
427 if out_buff_len >= 32 {
428 unsafe {
429 for i in 0..32 {
431 *out_buff_ptr.add(i) = 0xAA;
432 }
433 }
434 32
435 } else {
436 -1
437 }
438 },
439 );
440
441 let account = [0u8; 20]; let mut keylet_buffer = [0u8; 32];
444
445 unsafe {
446 let result = mock.account_keylet(
447 account.as_ptr(),
448 account.len(),
449 keylet_buffer.as_mut_ptr(),
450 keylet_buffer.len(),
451 );
452
453 assert_eq!(result, 32);
454 assert_eq!(keylet_buffer, [0xAA; 32]);
455 }
456 }
457
458 #[test]
459 fn test_error_conditions_with_mock() {
460 let mut mock = MockHostBindings::new();
461
462 mock.expect_get_ledger_sqn().times(1).returning(|_, _| -1); mock.expect_get_parent_ledger_hash()
466 .times(1)
467 .returning(|_out_buff_ptr, _out_buff_len| -2); unsafe {
470 let mut buffer = [0u8; 32];
472 assert_eq!(mock.get_ledger_sqn(buffer.as_mut_ptr(), buffer.len()), -1);
473
474 let mut small_buffer = [0u8; 16]; let result = mock.get_parent_ledger_hash(small_buffer.as_mut_ptr(), small_buffer.len());
476 assert_eq!(result, -2);
477 }
478 }
479
480 #[test]
481 fn test_generic_function_with_mock() {
482 fn get_ledger_info<H: HostBindings>(host: &H) -> (i32, i32, i32) {
484 let mut buffer = [0u8; 32];
485 unsafe {
486 let sqn = host.get_ledger_sqn(buffer.as_mut_ptr(), buffer.len());
487 let time = host.get_parent_ledger_time(buffer.as_mut_ptr(), buffer.len());
488 let fee = host.get_base_fee(buffer.as_mut_ptr(), buffer.len());
489 (sqn, time, fee)
490 }
491 }
492
493 let mut mock = MockHostBindings::new();
494
495 mock.expect_get_ledger_sqn().returning(|_, _| 999);
496 mock.expect_get_parent_ledger_time().returning(|_, _| 888);
497 mock.expect_get_base_fee().returning(|_, _| 777);
498
499 let (sqn, time, fee) = get_ledger_info(&mock);
500 assert_eq!(sqn, 999);
501 assert_eq!(time, 888);
502 assert_eq!(fee, 777);
503 }
504}