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_ldgr_index()
41 .returning(|_, out_buff_len| out_buff_len as i32);
42 mock.expect_parent_ldgr_time()
43 .returning(|_, out_buff_len| out_buff_len as i32);
44 mock.expect_base_fee()
45 .returning(|_, out_buff_len| out_buff_len as i32);
46
47 mock.expect_parent_ldgr_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_le()
53 .returning(|_, id_len, _| id_len as i32);
54 const STI_AMOUNT: i32 = 6;
61 mock.expect_tx_field().returning(|field, _, out_buff_len| {
62 if field >> 16 == STI_AMOUNT {
63 8
64 } else {
65 out_buff_len as i32
66 }
67 });
68 mock.expect_home_le_field()
69 .returning(|field, _, out_buff_len| {
70 if field >> 16 == STI_AMOUNT {
71 8
72 } else {
73 out_buff_len as i32
74 }
75 });
76 mock.expect_le_field()
77 .returning(|_, field, _, out_buff_len| {
78 if field >> 16 == STI_AMOUNT {
79 8
80 } else {
81 out_buff_len as i32
82 }
83 });
84 mock.expect_tx_inner()
85 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
86 mock.expect_home_le_inner()
87 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
88 mock.expect_le_inner()
89 .returning(|_, _, _, _, out_buff_len| out_buff_len as i32);
90
91 mock.expect_tx_arr_len().returning(|_| 0);
93 mock.expect_home_le_arr_len().returning(|_| 0);
94 mock.expect_le_arr_len().returning(|_, _| 0);
95 mock.expect_tx_inner_arr_len().returning(|_, _| 0);
96 mock.expect_home_le_inner_arr_len()
98 .returning(|_, locator_len| locator_len as i32);
99 mock.expect_le_inner_arr_len()
100 .returning(|_, _, locator_len| locator_len as i32);
101
102 mock.expect_set_data()
104 .returning(|_, data_len| data_len as i32);
105 mock.expect_sha512_half()
106 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
107 mock.expect_check_sig().returning(|_, _, _, _, _, _| 0);
108
109 mock.expect_accountroot_id()
111 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
112 mock.expect_amm_id()
113 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
114 mock.expect_check_id()
115 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
116 mock.expect_credential_id()
117 .returning(|_, _, _, _, _, _, _, out_buff_len| out_buff_len as i32);
118 mock.expect_delegate_id()
119 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
120 mock.expect_deposit_preauth_id()
121 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
122 mock.expect_did_id()
123 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
124 mock.expect_escrow_id()
125 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
126 mock.expect_trustline_id()
127 .returning(|_, _, _, _, _, _, _, out_buff_len| out_buff_len as i32);
128 mock.expect_mpt_issuance_id()
129 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
130 mock.expect_mptoken_id()
131 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
132 mock.expect_nft_offer_id()
133 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
134 mock.expect_offer_id()
135 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
136 mock.expect_oracle_id()
137 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
138 mock.expect_paychan_id()
139 .returning(|_, _, _, _, _, _, _, out_buff_len| out_buff_len as i32);
140 mock.expect_permissioned_domain_id()
141 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
142 mock.expect_signers_id()
143 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
144 mock.expect_ticket_id()
145 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
146 mock.expect_vault_id()
147 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
148 mock.expect_sponsorship_id()
149 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
150 mock.expect_loan_broker_id()
151 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
152 mock.expect_loan_id()
153 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
154
155 mock.expect_nft_uri()
157 .returning(|_, _, _, _, _, out_buff_len| out_buff_len as i32);
158 mock.expect_nft_issuer()
159 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
160 mock.expect_nft_taxon()
161 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
162 mock.expect_nft_flags()
163 .returning(|_, nft_id_len| nft_id_len as i32);
164 mock.expect_nft_xfer_fee()
165 .returning(|_, nft_id_len| nft_id_len as i32);
166 mock.expect_nft_serial()
167 .returning(|_, _, _, out_buff_len| out_buff_len as i32);
168
169 mock.expect_float_from_int()
171 .returning(|_, _, out_buff_len, _| out_buff_len as i32);
172 mock.expect_float_from_uint()
173 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
174 mock.expect_float_from_mant_exp()
175 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
176 mock.expect_float_from_stamount()
177 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
178 mock.expect_float_from_stnumber()
179 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
180 mock.expect_float_to_int()
181 .returning(|_, _, _, out_buff_len, _| out_buff_len as i32);
182 mock.expect_float_to_mant_exp()
183 .returning(|_, _, _, _, _, _| 8);
184 mock.expect_float_cmp().returning(|_, _, _, _| 0);
185 mock.expect_float_add()
186 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
187 mock.expect_float_sub()
188 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
189 mock.expect_float_mult()
190 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
191 mock.expect_float_div()
192 .returning(|_, _, _, _, _, out_buff_len, _| out_buff_len as i32);
193 mock.expect_float_pow()
194 .returning(|_, _, _, _, out_buff_len, _| out_buff_len as i32);
195
196 mock.expect_trace().returning(|_, _, _, _, _| ());
198}
199
200#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
202thread_local! {
203 static MOCK_STATE: RefCell<Option<MockHostBindings>> = RefCell::new(Some(create_default_mock()));
204}
205
206#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
208pub fn set_mock_host_bindings(mock: MockHostBindings) {
209 MOCK_STATE.with(|state| {
210 *state.borrow_mut() = Some(mock);
211 });
212}
213
214#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
215pub fn clear_mock_host_bindings() {
216 MOCK_STATE.with(|state| {
217 *state.borrow_mut() = None;
218 });
219}
220
221#[cfg(all(any(test, feature = "test-host-bindings"), not(target_arch = "wasm32")))]
222macro_rules! export_host_functions {
225 ($(
226 $(#[$attr:meta])*
227 fn $name:ident($($param:ident: $param_ty:ty),*) -> $ret:ty;
228 )*) => {
229 $(
230 #[allow(clippy::too_many_arguments)]
231 #[allow(clippy::missing_safety_doc)]
232 $(#[$attr])*
233 pub unsafe fn $name($($param: $param_ty),*) -> $ret {
234 MOCK_STATE.with(|state| {
235 let mock = state.borrow();
238 let mock_ref = mock.as_ref().expect("MockHostBindings not initialized");
239 unsafe { mock_ref.$name($($param),*) }
240 })
241 }
242 )*
243 };
244}
245
246export_host_functions! {
252 fn ldgr_index(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
254 fn parent_ldgr_time(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
255 fn parent_ldgr_hash(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
256 fn base_fee(out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
257 fn amendment_enabled(amendment_ptr: *const u8, amendment_len: usize) -> i32;
258 fn cache_le(id_ptr: *const u8, id_len: usize, cache_num: i32) -> i32;
259 fn tx_field(field: i32, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
260 fn home_le_field(field: i32, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
261 fn le_field(cache_num: i32, field: i32, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
262 fn tx_inner(locator_ptr: *const u8, locator_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
263 fn home_le_inner(locator_ptr: *const u8, locator_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
264 fn le_inner(cache_num: i32, locator_ptr: *const u8, locator_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
265 fn tx_arr_len(field: i32) -> i32;
266 fn home_le_arr_len(field: i32) -> i32;
267 fn le_arr_len(cache_num: i32, field: i32) -> i32;
268 fn tx_inner_arr_len(locator_ptr: *const u8, locator_len: usize) -> i32;
269 fn home_le_inner_arr_len(locator_ptr: *const u8, locator_len: usize) -> i32;
270 fn le_inner_arr_len(cache_num: i32, locator_ptr: *const u8, locator_len: usize) -> i32;
271
272 fn set_data(data_ptr: *const u8, data_len: usize) -> i32;
274
275 fn sha512_half(data_ptr: *const u8, data_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
277 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;
278 fn accountroot_id(account_ptr: *const u8, account_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
279 fn amm_id(issue1_ptr: *const u8, issue1_len: usize, issue2_ptr: *const u8, issue2_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
280 fn check_id(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 credential_id(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;
282 fn delegate_id(account_ptr: *const u8, account_len: usize, authorize_ptr: *const u8, authorize_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
283 fn deposit_preauth_id(account_ptr: *const u8, account_len: usize, authorize_ptr: *const u8, authorize_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
284 fn did_id(account_ptr: *const u8, account_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
285 fn escrow_id(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
286 fn trustline_id(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;
287 fn mpt_issuance_id(issuer_ptr: *const u8, issuer_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
288 fn mptoken_id(mptid_ptr: *const u8, mptid_len: usize, holder_ptr: *const u8, holder_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
289 fn nft_offer_id(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
290 fn offer_id(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
291 fn oracle_id(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;
292 fn paychan_id(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;
293 fn permissioned_domain_id(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
294 fn signers_id(account_ptr: *const u8, account_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
295 fn ticket_id(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
296 fn vault_id(account_ptr: *const u8, account_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
297 fn sponsorship_id(sponsor_ptr: *const u8, sponsor_len: usize, sponsee_ptr: *const u8, sponsee_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
298 fn loan_broker_id(owner_ptr: *const u8, owner_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
299 fn loan_id(loan_broker_id_ptr: *const u8, loan_broker_id_len: usize, sequence_ptr: *const u8, sequence_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
300
301 fn nft_uri(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;
303 fn nft_issuer(nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
304 fn nft_taxon(nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
305 fn nft_flags(nft_id_ptr: *const u8, nft_id_len: usize) -> i32;
306 fn nft_xfer_fee(nft_id_ptr: *const u8, nft_id_len: usize) -> i32;
307 fn nft_serial(nft_id_ptr: *const u8, nft_id_len: usize, out_buff_ptr: *mut u8, out_buff_len: usize) -> i32;
308
309 fn float_from_int(in_int: i64, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
311 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;
312 fn float_from_mant_exp(mantissa: i64, exponent: i32, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
313 fn float_from_stamount(in_buff: *const u8, in_buff_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
314 fn float_from_stnumber(in_buff: *const u8, in_buff_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
315 fn float_to_int(in_buff: *const u8, in_buff_len: usize, out_buff: *mut u8, out_buff_len: usize, rounding_mode: i32) -> i32;
316 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;
317 fn float_cmp(in_buff1: *const u8, in_buff1_len: usize, in_buff2: *const u8, in_buff2_len: usize) -> i32;
318 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;
319 fn float_sub(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;
320 fn float_mult(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;
321 fn float_div(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;
322 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;
323
324 fn trace(msg_read_ptr: *const u8, msg_read_len: usize, data_type: i32, data_read_ptr: *const u8, data_read_len: usize) -> ();
326
327}
328
329#[cfg(test)]
330mod tests {
331 use super::*;
332 use crate::host::trace::TraceDataType;
333
334 #[test]
335 fn test_ledger_functions_with_mock() {
336 let mut mock = MockHostBindings::new();
337
338 mock.expect_ldgr_index().times(1).returning(|_, _| 12345);
340 mock.expect_parent_ldgr_time()
341 .times(1)
342 .returning(|_, _| 1234567890);
343 mock.expect_base_fee().times(1).returning(|_, _| 10);
344
345 set_mock_host_bindings(mock);
347
348 let mut buffer = [0u8; 32];
350 unsafe {
351 assert_eq!(ldgr_index(buffer.as_mut_ptr(), buffer.len()), 12345);
352 assert_eq!(
353 parent_ldgr_time(buffer.as_mut_ptr(), buffer.len()),
354 1234567890
355 );
356 assert_eq!(base_fee(buffer.as_mut_ptr(), buffer.len()), 10);
357 }
358
359 clear_mock_host_bindings();
361 }
362
363 #[test]
364 fn test_buffer_operations_with_mock() {
365 let mut mock = MockHostBindings::new();
366
367 mock.expect_parent_ldgr_hash()
369 .times(1)
370 .returning(|out_buff_ptr, out_buff_len| {
371 if out_buff_len >= 32 {
372 unsafe {
373 for i in 0..32 {
375 *out_buff_ptr.add(i) = (i * 2) as u8;
376 }
377 }
378 32 } else {
380 -1 }
382 });
383
384 let mut buffer = [0u8; 32];
386 unsafe {
387 let result = mock.parent_ldgr_hash(buffer.as_mut_ptr(), buffer.len());
388 assert_eq!(result, 32);
389
390 for (i, _) in buffer.iter().enumerate() {
392 assert_eq!(buffer[i], (i * 2) as u8);
393 }
394 }
395 }
396
397 #[test]
398 fn test_trace_functions_with_mock() {
399 let mut mock = MockHostBindings::new();
400
401 mock.expect_trace()
402 .times(2)
403 .returning(|_msg_ptr, _msg_len, _data_type, _data_ptr, _data_len| ());
404
405 let message = b"Test message";
406 let data = b"Test data";
407 let number = 42i64.to_le_bytes();
408
409 unsafe {
410 mock.trace(
411 message.as_ptr(),
412 message.len(),
413 TraceDataType::AsText as i32,
414 data.as_ptr(),
415 data.len(),
416 );
417
418 mock.trace(
419 message.as_ptr(),
420 message.len(),
421 TraceDataType::Int64 as i32,
422 number.as_ptr(),
423 number.len(),
424 );
425 }
426 }
427
428 #[test]
429 fn test_id_functions_with_mock() {
430 let mut mock = MockHostBindings::new();
431
432 mock.expect_accountroot_id().times(1).returning(
434 |_account_ptr, _account_len, out_buff_ptr, out_buff_len| {
435 if out_buff_len >= 32 {
436 unsafe {
437 for i in 0..32 {
439 *out_buff_ptr.add(i) = 0xAA;
440 }
441 }
442 32
443 } else {
444 -1
445 }
446 },
447 );
448
449 let account = [0u8; 20]; let mut id_buffer = [0u8; 32];
452
453 unsafe {
454 let result = mock.accountroot_id(
455 account.as_ptr(),
456 account.len(),
457 id_buffer.as_mut_ptr(),
458 id_buffer.len(),
459 );
460
461 assert_eq!(result, 32);
462 assert_eq!(id_buffer, [0xAA; 32]);
463 }
464 }
465
466 #[test]
467 fn test_error_conditions_with_mock() {
468 let mut mock = MockHostBindings::new();
469
470 mock.expect_ldgr_index().times(1).returning(|_, _| -1); mock.expect_parent_ldgr_hash()
474 .times(1)
475 .returning(|_out_buff_ptr, _out_buff_len| -2); unsafe {
478 let mut buffer = [0u8; 32];
480 assert_eq!(mock.ldgr_index(buffer.as_mut_ptr(), buffer.len()), -1);
481
482 let mut small_buffer = [0u8; 16]; let result = mock.parent_ldgr_hash(small_buffer.as_mut_ptr(), small_buffer.len());
484 assert_eq!(result, -2);
485 }
486 }
487
488 #[test]
489 fn test_generic_function_with_mock() {
490 fn get_ledger_info<H: HostBindings>(host: &H) -> (i32, i32, i32) {
492 let mut buffer = [0u8; 32];
493 unsafe {
494 let sqn = host.ldgr_index(buffer.as_mut_ptr(), buffer.len());
495 let time = host.parent_ldgr_time(buffer.as_mut_ptr(), buffer.len());
496 let fee = host.base_fee(buffer.as_mut_ptr(), buffer.len());
497 (sqn, time, fee)
498 }
499 }
500
501 let mut mock = MockHostBindings::new();
502
503 mock.expect_ldgr_index().returning(|_, _| 999);
504 mock.expect_parent_ldgr_time().returning(|_, _| 888);
505 mock.expect_base_fee().returning(|_, _| 777);
506
507 let (sqn, time, fee) = get_ledger_info(&mock);
508 assert_eq!(sqn, 999);
509 assert_eq!(time, 888);
510 assert_eq!(fee, 777);
511 }
512}