xrpl_escrow_stdlib/current_tx/
traits.rs1use xrpl_common_stdlib::current_tx::get_field;
4use xrpl_common_stdlib::current_tx::traits::TransactionCommonFields;
5use xrpl_common_stdlib::host::error_codes::match_result_code_optional;
6use xrpl_common_stdlib::host::{Result, tx_field};
7use xrpl_common_stdlib::sfield;
8use xrpl_common_stdlib::types::account_id::AccountID;
9use xrpl_common_stdlib::types::blob::{ConditionBlob, FulfillmentBlob};
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 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 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_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::host::error_codes::{
155 FIELD_NOT_FOUND, INVALID_FIELD, SOME_ERROR,
156 };
157 use xrpl_common_stdlib::host::host_bindings_trait::MockHostBindings;
158 use xrpl_common_stdlib::host::setup_mock;
159 use xrpl_common_stdlib::sfield;
160 use xrpl_common_stdlib::types::blob::{CONDITION_BLOB_SIZE, FULFILLMENT_BLOB_SIZE};
161
162 use mockall::predicate::{always, eq};
163 use xrpl_common_stdlib::sfield::{Condition, Fulfillment};
164
165 #[test]
166 fn test_optional_fields_return_some() {
167 let mut mock = MockHostBindings::new();
168
169 expect_tx_field(&mut mock, Condition, CONDITION_BLOB_SIZE, 1);
171 expect_tx_field(&mut mock, Fulfillment, FULFILLMENT_BLOB_SIZE, 1);
173
174 let _guard = setup_mock(mock);
175
176 let escrow = EscrowFinish;
177
178 let condition = escrow.get_condition().unwrap();
180 assert!(condition.is_some());
181 assert_eq!(condition.unwrap().len, CONDITION_BLOB_SIZE);
182
183 let fulfillment = escrow.get_fulfillment().unwrap();
184 assert!(fulfillment.is_some());
185 assert_eq!(fulfillment.unwrap().len, FULFILLMENT_BLOB_SIZE);
186 }
187
188 #[test]
189 fn test_optional_fields_return_none_when_zero_length() {
190 let mut mock = MockHostBindings::new();
191
192 mock.expect_tx_field()
194 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
195 .times(1)
196 .returning(|_, _, _| 0);
197 mock.expect_tx_field()
199 .with(eq(sfield::Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
200 .times(1)
201 .returning(|_, _, _| 0);
202
203 let _guard = setup_mock(mock);
204
205 let escrow = EscrowFinish;
206
207 assert!(escrow.get_condition().unwrap().is_none());
209 assert!(escrow.get_fulfillment().unwrap().is_none());
210 }
211
212 #[test]
213 fn test_optional_fields_return_error_on_internal_error() {
214 let mut mock = MockHostBindings::new();
215
216 mock.expect_tx_field()
218 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
219 .times(1)
220 .returning(|_, _, _| SOME_ERROR);
221 mock.expect_tx_field()
223 .with(eq(sfield::Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
224 .times(1)
225 .returning(|_, _, _| SOME_ERROR);
226
227 let _guard = setup_mock(mock);
228
229 let escrow = EscrowFinish;
230
231 let condition_result = escrow.get_condition();
233 assert!(condition_result.is_err());
234 assert_eq!(condition_result.err().unwrap().code(), SOME_ERROR);
235
236 let fulfillment_result = escrow.get_fulfillment();
237 assert!(fulfillment_result.is_err());
238 assert_eq!(fulfillment_result.err().unwrap().code(), SOME_ERROR);
239 }
240
241 #[test]
242 fn test_optional_fields_return_error_on_field_not_found() {
243 let mut mock = MockHostBindings::new();
244
245 mock.expect_tx_field()
247 .with(eq(Condition), always(), eq(CONDITION_BLOB_SIZE))
248 .times(1)
249 .returning(|_, _, _| FIELD_NOT_FOUND);
250 mock.expect_tx_field()
252 .with(eq(Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
253 .times(1)
254 .returning(|_, _, _| FIELD_NOT_FOUND);
255
256 let _guard = setup_mock(mock);
257
258 let escrow = EscrowFinish;
259
260 let condition_result = escrow.get_condition();
262 assert!(condition_result.is_err());
263 assert_eq!(condition_result.err().unwrap().code(), FIELD_NOT_FOUND);
264
265 let fulfillment_result = escrow.get_fulfillment();
266 assert!(fulfillment_result.is_err());
267 assert_eq!(fulfillment_result.err().unwrap().code(), FIELD_NOT_FOUND);
268 }
269
270 #[test]
271 fn test_optional_fields_return_error_on_invalid_field() {
272 let mut mock = MockHostBindings::new();
273
274 mock.expect_tx_field()
276 .with(eq(sfield::Condition), always(), eq(CONDITION_BLOB_SIZE))
277 .times(1)
278 .returning(|_, _, _| INVALID_FIELD);
279 mock.expect_tx_field()
281 .with(eq(sfield::Fulfillment), always(), eq(FULFILLMENT_BLOB_SIZE))
282 .times(1)
283 .returning(|_, _, _| INVALID_FIELD);
284
285 let _guard = setup_mock(mock);
286
287 let escrow = EscrowFinish;
288
289 let condition_result = escrow.get_condition();
291 assert!(condition_result.is_err());
292 assert_eq!(condition_result.err().unwrap().code(), INVALID_FIELD);
293
294 let fulfillment_result = escrow.get_fulfillment();
295 assert!(fulfillment_result.is_err());
296 assert_eq!(fulfillment_result.err().unwrap().code(), INVALID_FIELD);
297 }
298 }
299
300 mod mandatory_fields {
301 use crate::current_tx::escrow_finish::EscrowFinish;
302 use crate::current_tx::traits::EscrowFinishFields;
303 use crate::current_tx::traits::tests::expect_tx_field;
304 use mockall::predicate::{always, eq};
305 use xrpl_common_stdlib::host::error_codes::{
306 FIELD_NOT_FOUND, INVALID_FIELD, SOME_ERROR,
307 };
308 use xrpl_common_stdlib::host::host_bindings_trait::MockHostBindings;
309 use xrpl_common_stdlib::host::setup_mock;
310 use xrpl_common_stdlib::sfield;
311 use xrpl_common_stdlib::types::account_id::ACCOUNT_ID_SIZE;
312
313 #[test]
314 fn test_mandatory_fields_return_ok() {
315 let mut mock = MockHostBindings::new();
316
317 expect_tx_field(&mut mock, sfield::Owner, ACCOUNT_ID_SIZE, 1);
319 expect_tx_field(&mut mock, sfield::OfferSequence, 4, 1);
321
322 let _guard = setup_mock(mock);
323
324 let escrow = EscrowFinish;
325
326 assert!(escrow.get_owner().is_ok());
328 assert!(escrow.get_offer_sequence().is_ok());
329 }
330
331 #[test]
335 fn test_get_owner_errors_when_zero_length() {
336 let mut mock = MockHostBindings::new();
337 mock.expect_tx_field()
338 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
339 .returning(|_, _, _| 0);
340
341 let _guard = setup_mock(mock);
342
343 let result = EscrowFinish.get_owner();
344 assert!(result.is_err());
345 assert_eq!(
346 result.err().unwrap().code(),
347 xrpl_common_stdlib::host::Error::InvalidDecoding.code()
348 );
349 }
350
351 #[test]
352 fn test_get_offer_sequence_errors_when_zero_length() {
353 let mut mock = MockHostBindings::new();
354 mock.expect_tx_field()
355 .with(eq(sfield::OfferSequence), always(), eq(4))
356 .returning(|_, _, _| 0);
357
358 let _guard = setup_mock(mock);
359
360 let result = EscrowFinish.get_offer_sequence();
361 assert!(result.is_err());
362 assert_eq!(
363 result.err().unwrap().code(),
364 xrpl_common_stdlib::host::Error::InvalidDecoding.code()
365 );
366 }
367
368 #[test]
369 fn test_mandatory_fields_return_error_on_field_not_found() {
370 let mut mock = MockHostBindings::new();
371
372 mock.expect_tx_field()
374 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
375 .times(1)
376 .returning(|_, _, _| FIELD_NOT_FOUND);
377 mock.expect_tx_field()
379 .with(eq(sfield::OfferSequence), always(), eq(4))
380 .times(1)
381 .returning(|_, _, _| FIELD_NOT_FOUND);
382
383 let _guard = setup_mock(mock);
384
385 let escrow = EscrowFinish;
386
387 let owner_result = escrow.get_owner();
389 assert!(owner_result.is_err());
390 assert_eq!(owner_result.err().unwrap().code(), FIELD_NOT_FOUND);
391
392 let offer_seq_result = escrow.get_offer_sequence();
393 assert!(offer_seq_result.is_err());
394 assert_eq!(offer_seq_result.err().unwrap().code(), FIELD_NOT_FOUND);
395 }
396
397 #[test]
398 fn test_mandatory_fields_return_error_on_internal_error() {
399 let mut mock = MockHostBindings::new();
400
401 mock.expect_tx_field()
403 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
404 .times(1)
405 .returning(|_, _, _| SOME_ERROR);
406 mock.expect_tx_field()
408 .with(eq(sfield::OfferSequence), always(), eq(4))
409 .times(1)
410 .returning(|_, _, _| SOME_ERROR);
411
412 let _guard = setup_mock(mock);
413
414 let escrow = EscrowFinish;
415
416 let owner_result = escrow.get_owner();
418 assert!(owner_result.is_err());
419 assert_eq!(owner_result.err().unwrap().code(), SOME_ERROR);
420
421 let offer_seq_result = escrow.get_offer_sequence();
422 assert!(offer_seq_result.is_err());
423 assert_eq!(offer_seq_result.err().unwrap().code(), SOME_ERROR);
424 }
425
426 #[test]
427 fn test_mandatory_fields_return_error_on_invalid_field() {
428 let mut mock = MockHostBindings::new();
429
430 mock.expect_tx_field()
432 .with(eq(sfield::Owner), always(), eq(ACCOUNT_ID_SIZE))
433 .times(1)
434 .returning(|_, _, _| INVALID_FIELD);
435 mock.expect_tx_field()
437 .with(eq(sfield::OfferSequence), always(), eq(4))
438 .times(1)
439 .returning(|_, _, _| INVALID_FIELD);
440
441 let _guard = setup_mock(mock);
442
443 let escrow = EscrowFinish;
444
445 let owner_result = escrow.get_owner();
447 assert!(owner_result.is_err());
448 assert_eq!(owner_result.err().unwrap().code(), INVALID_FIELD);
449
450 let offer_seq_result = escrow.get_offer_sequence();
451 assert!(offer_seq_result.is_err());
452 assert_eq!(offer_seq_result.err().unwrap().code(), INVALID_FIELD);
453 }
454 }
455 }
456}