xrpl_escrow_stdlib/current_tx/
traits.rs1use xrpl_common_stdlib::core::current_tx::get_field;
4use xrpl_common_stdlib::core::current_tx::traits::TransactionCommonFields;
5use xrpl_common_stdlib::core::types::account_id::AccountID;
6use xrpl_common_stdlib::core::types::blob::{ConditionBlob, FulfillmentBlob};
7use xrpl_common_stdlib::host::error_codes::match_result_code_optional;
8use xrpl_common_stdlib::host::{Result, get_tx_field};
9use xrpl_common_stdlib::sfield;
10
11pub trait EscrowFinishFields: TransactionCommonFields {
25 fn get_owner(&self) -> Result<AccountID> {
37 get_field(sfield::Owner)
38 }
39
40 fn get_offer_sequence(&self) -> Result<u32> {
53 get_field(sfield::OfferSequence)
54 }
55
56 fn get_condition(&self) -> Result<Option<ConditionBlob>> {
73 let mut buffer = ConditionBlob::new();
74 let result_code = unsafe {
75 get_tx_field(
76 sfield::Condition.into(),
77 buffer.data.as_mut_ptr(),
78 buffer.capacity(),
79 )
80 };
81 match_result_code_optional(result_code, || {
82 buffer.len = result_code as usize;
83 (result_code > 0).then_some(buffer)
84 })
85 }
86
87 fn get_fulfillment(&self) -> Result<Option<FulfillmentBlob>> {
114 let mut buffer = FulfillmentBlob::new();
115 let result_code = unsafe {
116 get_tx_field(
117 sfield::Fulfillment.into(),
118 buffer.data.as_mut_ptr(),
119 buffer.capacity(),
120 )
121 };
122 match_result_code_optional(result_code, || {
123 buffer.len = result_code as usize;
124 (result_code > 0).then_some(buffer)
125 })
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use mockall::predicate::{always, eq};
132 use xrpl_common_stdlib::host::host_bindings_trait::MockHostBindings;
133 use xrpl_common_stdlib::sfield::SField;
134
135 fn expect_tx_field<T: Send + std::fmt::Debug + PartialEq + 'static, const CODE: i32>(
137 mock: &mut MockHostBindings,
138 field: SField<T, CODE>,
139 size: usize,
140 times: usize,
141 ) {
142 mock.expect_get_tx_field()
143 .with(eq(field), always(), eq(size))
144 .times(times)
145 .returning(move |_, _, _| size as i32);
146 }
147
148 mod escrow_finish_fields {
149
150 mod optional_fields {
151 use crate::current_tx::escrow_finish::EscrowFinish;
152 use crate::current_tx::traits::EscrowFinishFields;
153 use crate::current_tx::traits::tests::expect_tx_field;
154 use xrpl_common_stdlib::core::types::blob::{
155 CONDITION_BLOB_SIZE, FULFILLMENT_BLOB_SIZE,
156 };
157 use xrpl_common_stdlib::host::error_codes::{
158 FIELD_NOT_FOUND, INTERNAL_ERROR, INVALID_FIELD,
159 };
160 use xrpl_common_stdlib::host::host_bindings_trait::MockHostBindings;
161 use xrpl_common_stdlib::host::setup_mock;
162 use xrpl_common_stdlib::sfield;
163
164 use mockall::predicate::{always, eq};
165 use xrpl_common_stdlib::sfield::{Condition, Fulfillment};
166
167 #[test]
168 fn test_optional_fields_return_some() {
169 let mut mock = MockHostBindings::new();
170
171 expect_tx_field(&mut mock, Condition, CONDITION_BLOB_SIZE, 1);
173 expect_tx_field(&mut mock, Fulfillment, FULFILLMENT_BLOB_SIZE, 1);
175
176 let _guard = setup_mock(mock);
177
178 let escrow = EscrowFinish;
179
180 let condition = escrow.get_condition().unwrap();
182 assert!(condition.is_some());
183 assert_eq!(condition.unwrap().len, CONDITION_BLOB_SIZE);
184
185 let fulfillment = escrow.get_fulfillment().unwrap();
186 assert!(fulfillment.is_some());
187 assert_eq!(fulfillment.unwrap().len, FULFILLMENT_BLOB_SIZE);
188 }
189
190 #[test]
191 fn test_optional_fields_return_none_when_zero_length() {
192 let mut mock = MockHostBindings::new();
193
194 mock.expect_get_tx_field()
196 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
197 .times(1)
198 .returning(|_, _, _| 0);
199 mock.expect_get_tx_field()
201 .with(eq(sfield::Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
202 .times(1)
203 .returning(|_, _, _| 0);
204
205 let _guard = setup_mock(mock);
206
207 let escrow = EscrowFinish;
208
209 assert!(escrow.get_condition().unwrap().is_none());
211 assert!(escrow.get_fulfillment().unwrap().is_none());
212 }
213
214 #[test]
215 fn test_optional_fields_return_error_on_internal_error() {
216 let mut mock = MockHostBindings::new();
217
218 mock.expect_get_tx_field()
220 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
221 .times(1)
222 .returning(|_, _, _| INTERNAL_ERROR);
223 mock.expect_get_tx_field()
225 .with(eq(sfield::Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
226 .times(1)
227 .returning(|_, _, _| INTERNAL_ERROR);
228
229 let _guard = setup_mock(mock);
230
231 let escrow = EscrowFinish;
232
233 let condition_result = escrow.get_condition();
235 assert!(condition_result.is_err());
236 assert_eq!(condition_result.err().unwrap().code(), INTERNAL_ERROR);
237
238 let fulfillment_result = escrow.get_fulfillment();
239 assert!(fulfillment_result.is_err());
240 assert_eq!(fulfillment_result.err().unwrap().code(), INTERNAL_ERROR);
241 }
242
243 #[test]
244 fn test_optional_fields_return_error_on_field_not_found() {
245 let mut mock = MockHostBindings::new();
246
247 mock.expect_get_tx_field()
249 .with(eq(Condition), always(), eq(CONDITION_BLOB_SIZE))
250 .times(1)
251 .returning(|_, _, _| FIELD_NOT_FOUND);
252 mock.expect_get_tx_field()
254 .with(eq(Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
255 .times(1)
256 .returning(|_, _, _| FIELD_NOT_FOUND);
257
258 let _guard = setup_mock(mock);
259
260 let escrow = EscrowFinish;
261
262 let condition_result = escrow.get_condition();
264 assert!(condition_result.is_err());
265 assert_eq!(condition_result.err().unwrap().code(), FIELD_NOT_FOUND);
266
267 let fulfillment_result = escrow.get_fulfillment();
268 assert!(fulfillment_result.is_err());
269 assert_eq!(fulfillment_result.err().unwrap().code(), FIELD_NOT_FOUND);
270 }
271
272 #[test]
273 fn test_optional_fields_return_error_on_invalid_field() {
274 let mut mock = MockHostBindings::new();
275
276 mock.expect_get_tx_field()
278 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
279 .times(1)
280 .returning(|_, _, _| INVALID_FIELD);
281 mock.expect_get_tx_field()
283 .with(eq(sfield::Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
284 .times(1)
285 .returning(|_, _, _| INVALID_FIELD);
286
287 let _guard = setup_mock(mock);
288
289 let escrow = EscrowFinish;
290
291 let condition_result = escrow.get_condition();
293 assert!(condition_result.is_err());
294 assert_eq!(condition_result.err().unwrap().code(), INVALID_FIELD);
295
296 let fulfillment_result = escrow.get_fulfillment();
297 assert!(fulfillment_result.is_err());
298 assert_eq!(fulfillment_result.err().unwrap().code(), INVALID_FIELD);
299 }
300 }
301
302 mod mandatory_fields {
303 use crate::current_tx::escrow_finish::EscrowFinish;
304 use crate::current_tx::traits::EscrowFinishFields;
305 use crate::current_tx::traits::tests::expect_tx_field;
306 use mockall::predicate::{always, eq};
307 use xrpl_common_stdlib::core::types::account_id::ACCOUNT_ID_SIZE;
308 use xrpl_common_stdlib::host::error_codes::{
309 FIELD_NOT_FOUND, INTERNAL_ERROR, INVALID_FIELD,
310 };
311 use xrpl_common_stdlib::host::host_bindings_trait::MockHostBindings;
312 use xrpl_common_stdlib::host::setup_mock;
313 use xrpl_common_stdlib::sfield;
314
315 #[test]
316 fn test_mandatory_fields_return_ok() {
317 let mut mock = MockHostBindings::new();
318
319 expect_tx_field(&mut mock, sfield::Owner, ACCOUNT_ID_SIZE, 1);
321 expect_tx_field(&mut mock, sfield::OfferSequence, 4, 1);
323
324 let _guard = setup_mock(mock);
325
326 let escrow = EscrowFinish;
327
328 assert!(escrow.get_owner().is_ok());
330 assert!(escrow.get_offer_sequence().is_ok());
331 }
332
333 #[test]
337 #[should_panic]
338 fn test_get_owner_panics_when_zero_length() {
339 let mut mock = MockHostBindings::new();
340 mock.expect_get_tx_field()
341 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
342 .returning(|_, _, _| 0);
343
344 let _guard = setup_mock(mock);
345
346 let _ = EscrowFinish.get_owner();
347 }
348
349 #[test]
350 #[should_panic]
351 fn test_get_offer_sequence_panics_when_zero_length() {
352 let mut mock = MockHostBindings::new();
353 mock.expect_get_tx_field()
354 .with(eq(sfield::OfferSequence), always(), eq(4))
355 .returning(|_, _, _| 0);
356
357 let _guard = setup_mock(mock);
358
359 let _ = EscrowFinish.get_offer_sequence();
360 }
361
362 #[test]
363 fn test_mandatory_fields_return_error_on_field_not_found() {
364 let mut mock = MockHostBindings::new();
365
366 mock.expect_get_tx_field()
368 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
369 .times(1)
370 .returning(|_, _, _| FIELD_NOT_FOUND);
371 mock.expect_get_tx_field()
373 .with(eq(sfield::OfferSequence), always(), eq(4))
374 .times(1)
375 .returning(|_, _, _| FIELD_NOT_FOUND);
376
377 let _guard = setup_mock(mock);
378
379 let escrow = EscrowFinish;
380
381 let owner_result = escrow.get_owner();
383 assert!(owner_result.is_err());
384 assert_eq!(owner_result.err().unwrap().code(), FIELD_NOT_FOUND);
385
386 let offer_seq_result = escrow.get_offer_sequence();
387 assert!(offer_seq_result.is_err());
388 assert_eq!(offer_seq_result.err().unwrap().code(), FIELD_NOT_FOUND);
389 }
390
391 #[test]
392 fn test_mandatory_fields_return_error_on_internal_error() {
393 let mut mock = MockHostBindings::new();
394
395 mock.expect_get_tx_field()
397 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
398 .times(1)
399 .returning(|_, _, _| INTERNAL_ERROR);
400 mock.expect_get_tx_field()
402 .with(eq(sfield::OfferSequence), always(), eq(4))
403 .times(1)
404 .returning(|_, _, _| INTERNAL_ERROR);
405
406 let _guard = setup_mock(mock);
407
408 let escrow = EscrowFinish;
409
410 let owner_result = escrow.get_owner();
412 assert!(owner_result.is_err());
413 assert_eq!(owner_result.err().unwrap().code(), INTERNAL_ERROR);
414
415 let offer_seq_result = escrow.get_offer_sequence();
416 assert!(offer_seq_result.is_err());
417 assert_eq!(offer_seq_result.err().unwrap().code(), INTERNAL_ERROR);
418 }
419
420 #[test]
421 fn test_mandatory_fields_return_error_on_invalid_field() {
422 let mut mock = MockHostBindings::new();
423
424 mock.expect_get_tx_field()
426 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
427 .times(1)
428 .returning(|_, _, _| INVALID_FIELD);
429 mock.expect_get_tx_field()
431 .with(eq(sfield::OfferSequence), always(), eq(4))
432 .times(1)
433 .returning(|_, _, _| INVALID_FIELD);
434
435 let _guard = setup_mock(mock);
436
437 let escrow = EscrowFinish;
438
439 let owner_result = escrow.get_owner();
441 assert!(owner_result.is_err());
442 assert_eq!(owner_result.err().unwrap().code(), INVALID_FIELD);
443
444 let offer_seq_result = escrow.get_offer_sequence();
445 assert!(offer_seq_result.is_err());
446 assert_eq!(offer_seq_result.err().unwrap().code(), INVALID_FIELD);
447 }
448 }
449 }
450}