1use memchr::memchr;
2use smallvec::SmallVec;
3
4use crate::error::FixError;
5use crate::field::{FIELD_KEY_VALUE_SEPARATOR, FIELD_SEPARATOR};
6use crate::message::Message;
7use crate::tag::{Tag, parse_tag};
8
9const DEFAULT_CAPACITY: usize = 32;
11
12pub struct Decoder {
33 offsets: SmallVec<[(Tag, u32, u32); DEFAULT_CAPACITY]>,
37}
38
39impl Default for Decoder {
40 fn default() -> Self {
41 Self::new()
42 }
43}
44
45impl Decoder {
46 pub fn new() -> Self {
48 Self {
49 offsets: SmallVec::new(),
50 }
51 }
52
53 pub fn with_capacity(capacity: usize) -> Self {
56 Self {
57 offsets: SmallVec::with_capacity(capacity),
58 }
59 }
60
61 pub fn decode<'a>(&'a mut self, buf: &'a [u8]) -> Result<Message<'a>, FixError> {
77 self.offsets.clear();
79
80 let mut pos = 0;
81 while pos < buf.len() {
82 let eq_pos = memchr(FIELD_KEY_VALUE_SEPARATOR, &buf[pos..])
84 .ok_or(FixError::IncompleteMessage)?
85 + pos;
86
87 let tag = parse_tag(&buf[pos..eq_pos])?;
88
89 let soh_pos = memchr(FIELD_SEPARATOR, &buf[eq_pos + 1..])
91 .ok_or(FixError::IncompleteMessage)?
92 + eq_pos
93 + 1;
94
95 self.offsets
97 .push((tag, (eq_pos + 1) as u32, soh_pos as u32));
98
99 pos = soh_pos + 1;
100 }
101
102 Ok(Message::new(buf, self.offsets.as_slice()))
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::error::FixError;
112 use crate::group;
113
114 #[test]
119 fn happy_empty_buffer() {
120 let mut dec = Decoder::new();
121 let msg = dec.decode(b"").unwrap();
122 assert_eq!(msg.len(), 0);
123 assert!(msg.is_empty());
124 }
125
126 #[test]
127 fn happy_single_field() {
128 let mut dec = Decoder::new();
129 let msg = dec.decode(b"8=FIX.4.2\x01").unwrap();
130 assert_eq!(msg.len(), 1);
131 let f = msg.field(0);
132 assert_eq!(f.tag, 8);
133 assert_eq!(f.value, b"FIX.4.2");
134 }
135
136 #[test]
137 fn happy_multiple_fields() {
138 let mut dec = Decoder::new();
139 let msg = dec.decode(b"8=FIX.4.2\x0135=D\x0149=SENDER\x01").unwrap();
140 assert_eq!(msg.len(), 3);
141 let f0 = msg.field(0);
142 assert_eq!(f0.tag, 8);
143 assert_eq!(f0.value, b"FIX.4.2");
144 let f1 = msg.field(1);
145 assert_eq!(f1.tag, 35);
146 assert_eq!(f1.value, b"D");
147 let f2 = msg.field(2);
148 assert_eq!(f2.tag, 49);
149 assert_eq!(f2.value, b"SENDER");
150 }
151
152 #[test]
153 fn happy_empty_value() {
154 let mut dec = Decoder::new();
156 let msg = dec.decode(b"35=\x01").unwrap();
157 assert_eq!(msg.len(), 1);
158 let f = msg.field(0);
159 assert_eq!(f.tag, 35);
160 assert_eq!(f.value, b"");
161 }
162
163 #[test]
164 fn happy_value_containing_equals() {
165 let mut dec = Decoder::new();
168 let msg = dec.decode(b"58=price=100\x0135=D\x01").unwrap();
169 assert_eq!(msg.len(), 2);
170 assert_eq!(msg.field(0).tag, 58);
171 assert_eq!(msg.field(0).value, b"price=100");
172 assert_eq!(msg.field(1).tag, 35);
173 assert_eq!(msg.field(1).value, b"D");
174 }
175
176 #[test]
177 fn happy_binary_value() {
178 let mut dec = Decoder::new();
180 let msg = dec.decode(b"95=3\x0196=\x02\x03\x04\x01").unwrap();
181 assert_eq!(msg.len(), 2);
182 assert_eq!(msg.field(1).tag, 96);
183 assert_eq!(msg.field(1).value, &[0x02u8, 0x03, 0x04]);
184 }
185
186 #[test]
187 fn happy_exactly_32_fields() {
188 let mut dec = Decoder::new();
190 let mut buf = Vec::new();
191 for i in 1u32..=32 {
192 buf.extend_from_slice(format!("{}=v\x01", i).as_bytes());
193 }
194 let msg = dec.decode(&buf).unwrap();
195 assert_eq!(msg.len(), 32);
196 for i in 0..32 {
197 assert_eq!(msg.field(i).tag, (i + 1) as u32);
198 assert_eq!(msg.field(i).value, b"v");
199 }
200 }
201
202 #[test]
203 fn happy_33_fields_spills_to_heap() {
204 let mut dec = Decoder::new();
206 let mut buf = Vec::new();
207 for i in 1u32..=33 {
208 buf.extend_from_slice(format!("{}=v\x01", i).as_bytes());
209 }
210 let msg = dec.decode(&buf).unwrap();
211 assert_eq!(msg.len(), 33);
212 assert_eq!(msg.field(32).tag, 33);
213 }
214
215 #[test]
220 fn reuse_decode_twice() {
221 let mut dec = Decoder::new();
222 {
223 let msg = dec.decode(b"8=FIX.4.2\x01").unwrap();
224 assert_eq!(msg.field(0).tag, 8);
225 } let msg2 = dec.decode(b"35=D\x01").unwrap();
227 assert_eq!(msg2.field(0).tag, 35);
228 assert_eq!(msg2.field(0).value, b"D");
229 }
230
231 #[test]
232 fn reuse_large_then_small() {
233 let mut dec = Decoder::new();
235 let mut big_buf = Vec::new();
236 for i in 1u32..=33 {
237 big_buf.extend_from_slice(format!("{}=v\x01", i).as_bytes());
238 }
239 {
240 let msg = dec.decode(&big_buf).unwrap();
241 assert_eq!(msg.len(), 33);
242 }
243 let msg2 = dec.decode(b"8=FIX.4.2\x01").unwrap();
244 assert_eq!(msg2.len(), 1);
245 assert_eq!(msg2.field(0).tag, 8);
246 }
247
248 #[test]
249 fn reuse_many_iterations_stable() {
250 let mut dec = Decoder::new();
251 let buf = b"8=FIX.4.2\x0135=D\x0149=SENDER\x01";
252 for _ in 0..1_000 {
253 let msg = dec.decode(buf).unwrap();
254 assert_eq!(msg.len(), 3);
255 assert_eq!(msg.field(0).tag, 8);
256 }
257 }
258
259 #[test]
264 fn incomplete_tag_only_no_equals() {
265 let mut dec = Decoder::new();
266 assert!(matches!(
267 dec.decode(b"8").unwrap_err(),
268 FixError::IncompleteMessage
269 ));
270 }
271
272 #[test]
273 fn incomplete_tag_equals_value_no_soh() {
274 let mut dec = Decoder::new();
275 assert!(matches!(
276 dec.decode(b"8=FIX.4.2").unwrap_err(),
277 FixError::IncompleteMessage
278 ));
279 }
280
281 #[test]
282 fn incomplete_first_field_ok_second_tag_no_equals() {
283 let mut dec = Decoder::new();
284 assert!(matches!(
285 dec.decode(b"8=FIX.4.2\x0135").unwrap_err(),
286 FixError::IncompleteMessage
287 ));
288 }
289
290 #[test]
291 fn incomplete_second_field_value_no_soh() {
292 let mut dec = Decoder::new();
293 assert!(matches!(
294 dec.decode(b"8=FIX.4.2\x0135=D").unwrap_err(),
295 FixError::IncompleteMessage
296 ));
297 }
298
299 #[test]
300 fn incomplete_only_soh_byte() {
301 let mut dec = Decoder::new();
303 assert!(matches!(
304 dec.decode(b"\x01").unwrap_err(),
305 FixError::IncompleteMessage
306 ));
307 }
308
309 #[test]
314 fn invalid_tag_empty_tag_leading_equals() {
315 let mut dec = Decoder::new();
317 assert!(matches!(
318 dec.decode(b"=val\x01").unwrap_err(),
319 FixError::InvalidTag
320 ));
321 }
322
323 #[test]
324 fn invalid_tag_non_digit_byte() {
325 let mut dec = Decoder::new();
326 assert!(matches!(
327 dec.decode(b"8X=val\x01").unwrap_err(),
328 FixError::InvalidTag
329 ));
330 }
331
332 #[test]
333 fn invalid_tag_overflow_ten_nines() {
334 let mut dec = Decoder::new();
336 assert!(matches!(
337 dec.decode(b"9999999999=val\x01").unwrap_err(),
338 FixError::InvalidTag
339 ));
340 }
341
342 #[test]
343 fn invalid_tag_one_past_u32_max() {
344 let mut dec = Decoder::new();
346 assert!(matches!(
347 dec.decode(b"4294967296=val\x01").unwrap_err(),
348 FixError::InvalidTag
349 ));
350 }
351
352 #[test]
353 fn invalid_tag_leading_space() {
354 let mut dec = Decoder::new();
355 assert!(matches!(
356 dec.decode(b" 8=val\x01").unwrap_err(),
357 FixError::InvalidTag
358 ));
359 }
360
361 #[test]
362 fn invalid_tag_trailing_space() {
363 let mut dec = Decoder::new();
364 assert!(matches!(
365 dec.decode(b"8 =val\x01").unwrap_err(),
366 FixError::InvalidTag
367 ));
368 }
369
370 #[test]
375 fn edge_single_byte_value() {
376 let mut dec = Decoder::new();
377 let msg = dec.decode(b"8=X\x01").unwrap();
378 assert_eq!(msg.field(0).value, b"X");
379 }
380
381 #[test]
382 fn edge_value_starts_with_soh() {
383 let mut dec = Decoder::new();
386 let err = dec.decode(b"8=\x01val\x01").unwrap_err();
387 assert!(matches!(err, FixError::IncompleteMessage));
388 }
389
390 #[test]
391 fn edge_value_then_bare_soh() {
392 let mut dec = Decoder::new();
395 let err = dec.decode(b"8=A\x01B\x01").unwrap_err();
396 assert!(matches!(err, FixError::IncompleteMessage));
397 }
398
399 #[test]
400 fn edge_back_to_back_soh() {
401 let mut dec = Decoder::new();
404 let err = dec.decode(b"8=\x01\x01").unwrap_err();
405 assert!(matches!(err, FixError::IncompleteMessage));
406 }
407
408 #[test]
409 fn edge_tag_zero() {
410 let mut dec = Decoder::new();
413 let msg = dec.decode(b"0=val\x01").unwrap();
414 assert_eq!(msg.field(0).tag, 0);
415 assert_eq!(msg.field(0).value, b"val");
416 }
417
418 #[test]
419 fn edge_tag_u32_max() {
420 let mut dec = Decoder::new();
422 let msg = dec.decode(b"4294967295=val\x01").unwrap();
423 assert_eq!(msg.field(0).tag, u32::MAX);
424 assert_eq!(msg.field(0).value, b"val");
425 }
426
427 #[test]
432 fn pos_long_value_next_field_correct() {
433 let mut dec = Decoder::new();
435 let long_val = vec![b'A'; 1000];
436 let mut buf = Vec::new();
437 buf.extend_from_slice(b"96=");
438 buf.extend_from_slice(&long_val);
439 buf.push(0x01);
440 buf.extend_from_slice(b"35=D\x01");
441 let msg = dec.decode(&buf).unwrap();
442 assert_eq!(msg.len(), 2);
443 assert_eq!(msg.field(0).tag, 96);
444 assert_eq!(msg.field(0).value.len(), 1000);
445 assert_eq!(msg.field(1).tag, 35);
446 assert_eq!(msg.field(1).value, b"D");
447 }
448
449 #[test]
450 fn pos_equals_in_first_value_does_not_confuse_second_tag_scan() {
451 let mut dec = Decoder::new();
454 let msg = dec.decode(b"58=a=b=c\x0135=D\x01").unwrap();
455 assert_eq!(msg.len(), 2);
456 assert_eq!(msg.field(0).tag, 58);
457 assert_eq!(msg.field(0).value, b"a=b=c");
458 assert_eq!(msg.field(1).tag, 35);
459 assert_eq!(msg.field(1).value, b"D");
460 }
461
462 #[test]
463 fn pos_message_ending_exactly_at_soh() {
464 let mut dec = Decoder::new();
466 let msg = dec.decode(b"8=FIX.4.2\x0135=D\x01").unwrap();
467 assert_eq!(msg.len(), 2);
468 assert_eq!(msg.field(1).value, b"D");
469 }
470
471 #[test]
476 fn with_capacity_exact_fit() {
477 let mut dec = Decoder::with_capacity(4);
478 let msg = dec
479 .decode(b"8=FIX.4.2\x0135=D\x0149=A\x0156=B\x01")
480 .unwrap();
481 assert_eq!(msg.len(), 4);
482 assert_eq!(msg.field(3).tag, 56);
483 assert_eq!(msg.field(3).value, b"B");
484 }
485
486 #[test]
487 fn with_capacity_one_spills_to_heap() {
488 let mut dec = Decoder::with_capacity(1);
490 let mut buf = Vec::new();
491 for i in 1u32..=33 {
492 buf.extend_from_slice(format!("{}=v\x01", i).as_bytes());
493 }
494 let msg = dec.decode(&buf).unwrap();
495 assert_eq!(msg.len(), 33);
496 assert_eq!(msg.field(32).tag, 33);
497 }
498
499 #[test]
504 fn group_single_misc_fee() {
505 let mut dec = Decoder::new();
508 let msg = dec
509 .decode(b"8=FIX.4.2\x019=50\x0135=J\x01136=1\x01137=10.50\x01138=USD\x01139=4\x01")
510 .unwrap();
511 assert_eq!(msg.len(), 7);
512
513 let fees: Vec<_> = msg.groups(&group::MISC_FEES).collect();
514 assert_eq!(fees.len(), 1);
515 assert_eq!(
516 fees[0].find(crate::tag::MISC_FEE_AMT).unwrap().value,
517 b"10.50"
518 );
519 assert_eq!(
520 fees[0].find(crate::tag::MISC_FEE_CURR).unwrap().value,
521 b"USD"
522 );
523 assert_eq!(fees[0].find(crate::tag::MISC_FEE_TYPE).unwrap().value, b"4");
524 }
525
526 #[test]
527 fn group_multiple_misc_fees() {
528 let mut dec = Decoder::new();
530 let msg = dec
531 .decode(
532 b"35=J\x01136=2\x01137=5.00\x01138=USD\x01139=1\x01137=2.50\x01138=EUR\x01139=2\x01",
533 )
534 .unwrap();
535 assert_eq!(msg.len(), 8);
536
537 let fees: Vec<_> = msg.groups(&group::MISC_FEES).collect();
538 assert_eq!(fees.len(), 2);
539
540 assert_eq!(
541 fees[0].find(crate::tag::MISC_FEE_AMT).unwrap().value,
542 b"5.00"
543 );
544 assert_eq!(
545 fees[0].find(crate::tag::MISC_FEE_CURR).unwrap().value,
546 b"USD"
547 );
548 assert_eq!(fees[0].find(crate::tag::MISC_FEE_TYPE).unwrap().value, b"1");
549
550 assert_eq!(
551 fees[1].find(crate::tag::MISC_FEE_AMT).unwrap().value,
552 b"2.50"
553 );
554 assert_eq!(
555 fees[1].find(crate::tag::MISC_FEE_CURR).unwrap().value,
556 b"EUR"
557 );
558 assert_eq!(fees[1].find(crate::tag::MISC_FEE_TYPE).unwrap().value, b"2");
559 }
560
561 #[test]
562 fn group_md_entries_bid_and_offer() {
563 let mut dec = Decoder::new();
566 let msg = dec
567 .decode(
568 b"35=W\x0149=SENDER\x0156=TARGET\x01268=2\x01\
569 269=0\x01270=99.50\x01271=1000\x01\
570 269=1\x01270=99.75\x01271=500\x01",
571 )
572 .unwrap();
573 assert_eq!(msg.len(), 10);
574
575 let entries: Vec<_> = msg.groups(&group::MD_ENTRIES).collect();
576 assert_eq!(entries.len(), 2);
577
578 assert_eq!(
580 entries[0].find(crate::tag::MD_ENTRY_TYPE).unwrap().value,
581 b"0"
582 );
583 assert_eq!(
584 entries[0].find(crate::tag::MD_ENTRY_PX).unwrap().value,
585 b"99.50"
586 );
587 assert_eq!(
588 entries[0].find(crate::tag::MD_ENTRY_SIZE).unwrap().value,
589 b"1000"
590 );
591
592 assert_eq!(
594 entries[1].find(crate::tag::MD_ENTRY_TYPE).unwrap().value,
595 b"1"
596 );
597 assert_eq!(
598 entries[1].find(crate::tag::MD_ENTRY_PX).unwrap().value,
599 b"99.75"
600 );
601 assert_eq!(
602 entries[1].find(crate::tag::MD_ENTRY_SIZE).unwrap().value,
603 b"500"
604 );
605 }
606
607 #[test]
608 fn group_routing_ids_two_routes() {
609 let mut dec = Decoder::new();
611 let msg = dec
612 .decode(b"35=D\x01215=2\x01216=1\x01217=ROUTE_A\x01216=2\x01217=ROUTE_B\x01")
613 .unwrap();
614 assert_eq!(msg.len(), 6);
615
616 let routes: Vec<_> = msg.groups(&group::ROUTING_IDS).collect();
617 assert_eq!(routes.len(), 2);
618 assert_eq!(
619 routes[0].find(crate::tag::ROUTING_TYPE).unwrap().value,
620 b"1"
621 );
622 assert_eq!(
623 routes[0].find(crate::tag::ROUTING_ID).unwrap().value,
624 b"ROUTE_A"
625 );
626 assert_eq!(
627 routes[1].find(crate::tag::ROUTING_TYPE).unwrap().value,
628 b"2"
629 );
630 assert_eq!(
631 routes[1].find(crate::tag::ROUTING_ID).unwrap().value,
632 b"ROUTE_B"
633 );
634 }
635
636 #[test]
637 fn group_count_zero_yields_no_instances() {
638 let mut dec = Decoder::new();
640 let msg = dec.decode(b"35=J\x01136=0\x0158=no fees\x01").unwrap();
641 assert_eq!(msg.len(), 3);
642 assert_eq!(msg.groups(&group::MISC_FEES).count(), 0);
643 }
644
645 #[test]
646 fn group_count_tag_absent_yields_no_instances() {
647 let mut dec = Decoder::new();
649 let msg = dec.decode(b"8=FIX.4.2\x0135=D\x0149=SENDER\x01").unwrap();
650 assert_eq!(msg.groups(&group::MISC_FEES).count(), 0);
651 }
652
653 #[test]
654 fn group_fields_after_group_still_accessible() {
655 let mut dec = Decoder::new();
658 let msg = dec
659 .decode(b"35=J\x01136=1\x01137=3.00\x01138=USD\x01139=1\x0110=200\x01")
660 .unwrap();
661 assert_eq!(msg.len(), 6);
662
663 let fee = msg.groups(&group::MISC_FEES).next().unwrap();
665 assert_eq!(fee.find(crate::tag::MISC_FEE_AMT).unwrap().value, b"3.00");
666
667 assert_eq!(msg.find(crate::tag::CHECK_SUM).unwrap().value, b"200");
669 }
670
671 #[test]
676 fn all_groups_empty_message_yields_nothing() {
677 let mut dec = Decoder::new();
679 let msg = dec.decode(b"").unwrap();
680 assert_eq!(msg.all_groups().count(), 0);
681 }
682
683 #[test]
684 fn all_groups_no_group_tags_yields_nothing() {
685 let mut dec = Decoder::new();
687 let msg = dec.decode(b"8=FIX.4.2\x0135=D\x0149=SENDER\x01").unwrap();
688 assert_eq!(msg.all_groups().count(), 0);
689 }
690
691 #[test]
692 fn all_groups_single_group_present() {
693 let mut dec = Decoder::new();
695 let msg = dec
696 .decode(b"35=J\x01136=1\x01137=7.00\x01138=USD\x01139=2\x01")
697 .unwrap();
698
699 let mut iter = msg.all_groups();
700 let (spec, mut instances) = iter.next().expect("expected one group");
701 assert_eq!(spec.count_tag, crate::tag::NO_MISC_FEES);
702
703 let g = instances.next().unwrap();
704 assert_eq!(g.find(crate::tag::MISC_FEE_AMT).unwrap().value, b"7.00");
705 assert_eq!(g.find(crate::tag::MISC_FEE_CURR).unwrap().value, b"USD");
706 assert!(iter.next().is_none());
707 }
708
709 #[test]
710 fn all_groups_two_different_groups_present() {
711 let mut dec = Decoder::new();
713 let msg = dec
714 .decode(
715 b"35=D\x01215=2\x01216=1\x01217=ROUTE_A\x01216=2\x01217=ROUTE_B\x01\
716 136=1\x01137=1.00\x01138=USD\x01139=3\x01",
717 )
718 .unwrap();
719
720 let found: Vec<_> = msg.all_groups().map(|(spec, _)| spec.count_tag).collect();
721 assert!(found.contains(&crate::tag::NO_MISC_FEES));
723 assert!(found.contains(&crate::tag::NO_ROUTING_IDS));
724 assert_eq!(found.len(), 2);
725 }
726
727 #[test]
728 fn all_groups_count_zero_skipped() {
729 let mut dec = Decoder::new();
731 let msg = dec.decode(b"35=J\x01136=0\x01").unwrap();
732 assert_eq!(msg.all_groups().count(), 0);
733 }
734
735 #[test]
736 fn all_groups_instances_are_correct() {
737 let mut dec = Decoder::new();
739 let msg = dec
740 .decode(b"35=W\x01268=2\x01269=0\x01270=50.00\x01269=1\x01270=50.25\x01")
741 .unwrap();
742
743 let mut all = msg.all_groups();
744 let (spec, instances) = all.next().expect("expected MD_ENTRIES group");
745 assert_eq!(spec.count_tag, crate::tag::NO_MD_ENTRIES);
746
747 let entries: Vec<_> = instances.collect();
748 assert_eq!(entries.len(), 2);
749 assert_eq!(
750 entries[0].find(crate::tag::MD_ENTRY_TYPE).unwrap().value,
751 b"0"
752 );
753 assert_eq!(
754 entries[0].find(crate::tag::MD_ENTRY_PX).unwrap().value,
755 b"50.00"
756 );
757 assert_eq!(
758 entries[1].find(crate::tag::MD_ENTRY_TYPE).unwrap().value,
759 b"1"
760 );
761 assert_eq!(
762 entries[1].find(crate::tag::MD_ENTRY_PX).unwrap().value,
763 b"50.25"
764 );
765
766 assert!(all.next().is_none());
767 }
768
769 #[test]
777 fn validate_body_length_correct() {
778 let mut dec = Decoder::new();
781 let msg = dec
782 .decode(b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01")
783 .unwrap();
784 assert!(msg.validate_body_length().is_ok());
785 }
786
787 #[test]
788 fn validate_body_length_wrong_value() {
789 let mut dec = Decoder::new();
791 let msg = dec
792 .decode(b"8=FIX.4.2\x019=99\x0135=D\x0110=000\x01")
793 .unwrap();
794 assert!(matches!(
795 msg.validate_body_length().unwrap_err(),
796 FixError::InvalidBodyLength
797 ));
798 }
799
800 #[test]
801 fn validate_body_length_multi_field_body() {
802 let mut dec = Decoder::new();
805 let msg = dec
806 .decode(b"8=FIX.4.2\x019=25\x0135=D\x0149=SENDER\x0156=TARGET\x0110=195\x01")
807 .unwrap();
808 assert!(msg.validate_body_length().is_ok());
809 }
810
811 #[test]
812 fn validate_body_length_tag9_missing() {
813 let mut dec = Decoder::new();
815 let msg = dec.decode(b"8=FIX.4.2\x0135=D\x01").unwrap();
816 assert!(matches!(
817 msg.validate_body_length().unwrap_err(),
818 FixError::InvalidBodyLength
819 ));
820 }
821
822 #[test]
823 fn validate_body_length_tag9_not_second_field() {
824 let mut dec = Decoder::new();
826 let msg = dec
827 .decode(b"8=FIX.4.2\x0135=D\x019=5\x0110=000\x01")
828 .unwrap();
829 assert!(matches!(
830 msg.validate_body_length().unwrap_err(),
831 FixError::InvalidBodyLength
832 ));
833 }
834
835 #[test]
836 fn validate_body_length_tag10_not_last_field() {
837 let mut dec = Decoder::new();
839 let msg = dec
840 .decode(b"8=FIX.4.2\x019=5\x0110=000\x0135=D\x01")
841 .unwrap();
842 assert!(matches!(
843 msg.validate_body_length().unwrap_err(),
844 FixError::InvalidBodyLength
845 ));
846 }
847
848 #[test]
849 fn validate_checksum_correct() {
850 let mut dec = Decoder::new();
853 let msg = dec
854 .decode(b"8=FIX.4.2\x019=5\x0135=D\x0110=181\x01")
855 .unwrap();
856 assert!(msg.validate_checksum().is_ok());
857 }
858
859 #[test]
860 fn validate_checksum_wrong_value() {
861 let mut dec = Decoder::new();
863 let msg = dec
864 .decode(b"8=FIX.4.2\x019=5\x0135=D\x0110=000\x01")
865 .unwrap();
866 assert!(matches!(
867 msg.validate_checksum().unwrap_err(),
868 FixError::InvalidCheckSum
869 ));
870 }
871
872 #[test]
873 fn validate_checksum_multi_field_body() {
874 let mut dec = Decoder::new();
877 let msg = dec
878 .decode(b"8=FIX.4.2\x019=25\x0135=D\x0149=SENDER\x0156=TARGET\x0110=195\x01")
879 .unwrap();
880 assert!(msg.validate_checksum().is_ok());
881 }
882
883 #[test]
884 fn validate_checksum_tag10_missing() {
885 let mut dec = Decoder::new();
887 let msg = dec.decode(b"8=FIX.4.2\x0135=D\x01").unwrap();
888 assert!(matches!(
889 msg.validate_checksum().unwrap_err(),
890 FixError::InvalidCheckSum
891 ));
892 }
893
894 #[test]
895 fn validate_checksum_tag10_not_last_field() {
896 let mut dec = Decoder::new();
898 let msg = dec.decode(b"8=FIX.4.2\x0110=181\x0135=D\x01").unwrap();
899 assert!(matches!(
900 msg.validate_checksum().unwrap_err(),
901 FixError::InvalidCheckSum
902 ));
903 }
904
905 #[test]
906 fn validate_both_correct_together() {
907 let mut dec = Decoder::new();
909 let msg = dec
910 .decode(b"8=FIX.4.2\x019=25\x0135=D\x0149=SENDER\x0156=TARGET\x0110=195\x01")
911 .unwrap();
912 assert!(msg.validate_body_length().is_ok());
913 assert!(msg.validate_checksum().is_ok());
914 }
915}