From 13b9ca356c631020de24dea0af927b3a3b1fdd99 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 4 Dec 2023 17:55:56 +0100 Subject: [PATCH] added another finished PDU test --- src/cfdp/pdu/ack.rs | 50 +++++++++++++++++++++++++----------- src/cfdp/pdu/finished.rs | 44 ++++++++++++++++++++++++++++++++ src/cfdp/tlv/mod.rs | 36 ++++++++++++++++++++++++++ src/cfdp/tlv/msg_to_user.rs | 51 +++++++++++++++++++++++++++++++++++-- src/ecss/mod.rs | 8 +++--- src/util.rs | 26 +++++++++++-------- 6 files changed, 183 insertions(+), 32 deletions(-) diff --git a/src/cfdp/pdu/ack.rs b/src/cfdp/pdu/ack.rs index bc74911..355a44b 100644 --- a/src/cfdp/pdu/ack.rs +++ b/src/cfdp/pdu/ack.rs @@ -201,6 +201,24 @@ mod tests { use super::*; + fn verify_state(ack_pdu: &AckPdu, expected_crc_flag: CrcFlag, expected_dir: Direction) { + assert_eq!(ack_pdu.condition_code(), ConditionCode::NoError); + assert_eq!(ack_pdu.transaction_status(), TransactionStatus::Active); + + assert_eq!(ack_pdu.crc_flag(), expected_crc_flag); + assert_eq!(ack_pdu.file_flag(), LargeFileFlag::Normal); + assert_eq!(ack_pdu.pdu_type(), PduType::FileDirective); + assert_eq!( + ack_pdu.file_directive_type(), + Some(FileDirectiveType::AckPdu) + ); + assert_eq!(ack_pdu.transmission_mode(), TransmissionMode::Acknowledged); + assert_eq!(ack_pdu.direction(), expected_dir); + assert_eq!(ack_pdu.source_id(), TEST_SRC_ID.into()); + assert_eq!(ack_pdu.dest_id(), TEST_DEST_ID.into()); + assert_eq!(ack_pdu.transaction_seq_num(), TEST_SEQ_NUM.into()); + } + #[test] fn test_basic() { let pdu_conf = common_pdu_conf(CrcFlag::NoCrc, LargeFileFlag::Normal); @@ -216,21 +234,7 @@ mod tests { ack_pdu.directive_code_of_acked_pdu(), FileDirectiveType::FinishedPdu ); - assert_eq!(ack_pdu.condition_code(), ConditionCode::NoError); - assert_eq!(ack_pdu.transaction_status(), TransactionStatus::Active); - - assert_eq!(ack_pdu.crc_flag(), CrcFlag::NoCrc); - assert_eq!(ack_pdu.file_flag(), LargeFileFlag::Normal); - assert_eq!(ack_pdu.pdu_type(), PduType::FileDirective); - assert_eq!( - ack_pdu.file_directive_type(), - Some(FileDirectiveType::AckPdu) - ); - assert_eq!(ack_pdu.transmission_mode(), TransmissionMode::Acknowledged); - assert_eq!(ack_pdu.direction(), Direction::TowardsReceiver); - assert_eq!(ack_pdu.source_id(), TEST_SRC_ID.into()); - assert_eq!(ack_pdu.dest_id(), TEST_DEST_ID.into()); - assert_eq!(ack_pdu.transaction_seq_num(), TEST_SEQ_NUM.into()); + verify_state(&ack_pdu, CrcFlag::NoCrc, Direction::TowardsReceiver); } fn generic_serialization_test( @@ -296,4 +300,20 @@ mod tests { AckPdu::from_bytes(&ack_vec).expect("ACK PDU deserialization failed"); assert_eq!(ack_deserialized, ack_pdu); } + + #[test] + fn test_for_eof_pdu() { + let pdu_conf = common_pdu_conf(CrcFlag::WithCrc, LargeFileFlag::Normal); + let pdu_header = PduHeader::new_no_file_data(pdu_conf, 0); + let ack_pdu = AckPdu::new_for_eof_pdu( + pdu_header, + ConditionCode::NoError, + TransactionStatus::Active, + ); + assert_eq!( + ack_pdu.directive_code_of_acked_pdu(), + FileDirectiveType::EofPdu + ); + verify_state(&ack_pdu, CrcFlag::WithCrc, Direction::TowardsSender); + } } diff --git a/src/cfdp/pdu/finished.rs b/src/cfdp/pdu/finished.rs index b115f8e..c423f08 100644 --- a/src/cfdp/pdu/finished.rs +++ b/src/cfdp/pdu/finished.rs @@ -334,6 +334,7 @@ mod tests { let written = finished_pdu.write_to_bytes(&mut buf); assert!(written.is_ok()); let written = written.unwrap(); + assert_eq!(written, 9); assert_eq!(written, finished_pdu.len_written()); assert_eq!(written, finished_pdu.pdu_header().header_len() + 2); assert_eq!( @@ -423,4 +424,47 @@ mod tests { panic!("expected crc error"); } } + + #[test] + fn test_with_fault_location() { + let pdu_header = + PduHeader::new_no_file_data(common_pdu_conf(CrcFlag::NoCrc, LargeFileFlag::Normal), 0); + let finished_pdu = FinishedPdu::new_with_error( + pdu_header, + ConditionCode::NakLimitReached, + DeliveryCode::Incomplete, + FileStatus::DiscardDeliberately, + EntityIdTlv::new(TEST_DEST_ID.into()), + ); + let finished_pdu_vec = finished_pdu.to_vec().unwrap(); + assert_eq!(finished_pdu_vec.len(), 12); + assert_eq!(finished_pdu_vec[9], TlvType::EntityId.into()); + assert_eq!(finished_pdu_vec[10], 1); + assert_eq!(finished_pdu_vec[11], TEST_DEST_ID.value()); + assert_eq!( + finished_pdu.fault_location().unwrap().entity_id(), + &TEST_DEST_ID.into() + ); + } + + #[test] + fn test_deserialization_with_fault_location() { + let pdu_header = + PduHeader::new_no_file_data(common_pdu_conf(CrcFlag::NoCrc, LargeFileFlag::Normal), 0); + let entity_id_tlv = EntityIdTlv::new(TEST_DEST_ID.into()); + let finished_pdu = FinishedPdu::new_with_error( + pdu_header, + ConditionCode::NakLimitReached, + DeliveryCode::Incomplete, + FileStatus::DiscardDeliberately, + entity_id_tlv, + ); + let finished_pdu_vec = finished_pdu.to_vec().unwrap(); + let finished_pdu_deserialized = FinishedPdu::from_bytes(&finished_pdu_vec).unwrap(); + assert!(finished_pdu_deserialized.fault_location().is_some()); + assert_eq!( + finished_pdu_deserialized.fault_location().unwrap(), + entity_id_tlv + ) + } } diff --git a/src/cfdp/tlv/mod.rs b/src/cfdp/tlv/mod.rs index ae83094..c711a23 100644 --- a/src/cfdp/tlv/mod.rs +++ b/src/cfdp/tlv/mod.rs @@ -131,6 +131,13 @@ impl<'data> Tlv<'data> { }) } + pub fn new_with_custom_type(tlv_type: u8, data: &[u8]) -> Result { + Ok(Tlv { + tlv_type_field: TlvTypeField::Custom(tlv_type), + lv: Lv::new(data)?, + }) + } + /// Creates a TLV with an empty value field. pub fn new_empty(tlv_type: TlvType) -> Tlv<'data> { Tlv { @@ -608,10 +615,24 @@ mod tests { let mut buf: [u8; 16] = [0; 16]; let written_len = entity_id_tlv.write_to_bytes(&mut buf).unwrap(); assert_eq!(written_len, entity_id_tlv.len_full()); + assert_eq!(entity_id_tlv.len_value(), 2); assert!(entity_id_tlv.is_standard_tlv()); + assert_eq!(entity_id_tlv.tlv_type().unwrap(), TlvType::EntityId); assert_eq!(buf[0], TlvType::EntityId as u8); assert_eq!(buf[1], 2); assert_eq!(u16::from_be_bytes(buf[2..4].try_into().unwrap()), 0x0102); + let entity_id_as_vec = entity_id_tlv.to_vec(); + assert_eq!(entity_id_as_vec, buf[0..written_len].to_vec()); + } + + #[test] + fn test_entity_id_from_generic_tlv() { + let entity_id = UbfU16::new(0x0102); + let entity_id_tlv = EntityIdTlv::new(entity_id.into()); + let mut buf: [u8; 16] = [0; 16]; + let entity_id_as_tlv: Tlv = entity_id_tlv.to_tlv(&mut buf).unwrap(); + let entity_id_converted_back: EntityIdTlv = entity_id_as_tlv.try_into().unwrap(); + assert_eq!(entity_id_converted_back, entity_id_tlv); } #[test] @@ -932,4 +953,19 @@ mod tests { panic!("unexpected error"); } } + + #[test] + fn test_custom_tlv() { + let custom_tlv = Tlv::new_with_custom_type(20, &[]).unwrap(); + assert!(custom_tlv.tlv_type().is_none()); + if let TlvTypeField::Custom(val) = custom_tlv.tlv_type_field() { + assert_eq!(val, 20); + } else { + panic!("unexpected type field"); + } + let tlv_as_vec = custom_tlv.to_vec(); + assert_eq!(tlv_as_vec.len(), 2); + assert_eq!(tlv_as_vec[0], 20); + assert_eq!(tlv_as_vec[1], 0); + } } diff --git a/src/cfdp/tlv/msg_to_user.rs b/src/cfdp/tlv/msg_to_user.rs index 9ccd0be..17cdb0f 100644 --- a/src/cfdp/tlv/msg_to_user.rs +++ b/src/cfdp/tlv/msg_to_user.rs @@ -57,7 +57,7 @@ impl<'data> MsgToUserTlv<'data> { let msg_to_user = Self { tlv: Tlv::from_bytes(buf)?, }; - match msg_to_user.tlv_type_field() { + match msg_to_user.tlv.tlv_type_field() { TlvTypeField::Standard(tlv_type) => { if tlv_type != TlvType::MsgToUser { return Err(TlvLvError::InvalidTlvTypeField { @@ -91,13 +91,14 @@ impl WritableTlv for MsgToUserTlv<'_> { impl GenericTlv for MsgToUserTlv<'_> { fn tlv_type_field(&self) -> TlvTypeField { - TlvTypeField::Standard(TlvType::MsgToUser) + self.tlv.tlv_type_field() } } #[cfg(test)] mod tests { use super::*; + #[test] fn test_basic() { let custom_value: [u8; 4] = [1, 2, 3, 4]; @@ -106,6 +107,10 @@ mod tests { let msg_to_user = msg_to_user.unwrap(); assert!(msg_to_user.is_standard_tlv()); assert_eq!(msg_to_user.tlv_type().unwrap(), TlvType::MsgToUser); + assert_eq!( + msg_to_user.tlv_type_field(), + TlvTypeField::Standard(TlvType::MsgToUser) + ); assert_eq!(msg_to_user.value(), custom_value); assert_eq!(msg_to_user.value().len(), 4); assert_eq!(msg_to_user.len_value(), 4); @@ -115,6 +120,48 @@ mod tests { assert!(!msg_to_user.is_reserved_cfdp_msg()); } + #[test] + fn test_reserved_msg_serialization() { + let custom_value: [u8; 4] = [1, 2, 3, 4]; + let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap(); + let mut buf: [u8; 6] = [0; 6]; + msg_to_user.write_to_bytes(&mut buf).unwrap(); + assert_eq!( + buf, + [ + TlvType::MsgToUser as u8, + custom_value.len() as u8, + 1, + 2, + 3, + 4 + ] + ); + } + + #[test] + fn test_reserved_msg_deserialization() { + let custom_value: [u8; 3] = [1, 2, 3]; + let msg_to_user = MsgToUserTlv::new(&custom_value).unwrap(); + let msg_to_user_vec = msg_to_user.to_vec(); + let msg_to_user_from_bytes = MsgToUserTlv::from_bytes(&msg_to_user_vec).unwrap(); + assert!(!msg_to_user.is_reserved_cfdp_msg()); + assert_eq!(msg_to_user_from_bytes, msg_to_user); + assert_eq!(msg_to_user_from_bytes.value(), msg_to_user.value()); + assert_eq!(msg_to_user_from_bytes.tlv_type(), msg_to_user.tlv_type()); + } + #[test] + fn test_reserved_msg_deserialization_invalid_type() { + let trash: [u8; 5] = [TlvType::FlowLabel as u8, 3, 1, 2, 3]; + let error = MsgToUserTlv::from_bytes(&trash).unwrap_err(); + if let TlvLvError::InvalidTlvTypeField { found, expected } = error { + assert_eq!(found, TlvType::FlowLabel as u8); + assert_eq!(expected, Some(TlvType::MsgToUser as u8)); + } else { + panic!("Wrong error type returned: {:?}", error); + } + } + #[test] fn test_reserved_msg() { let reserved_str = "cfdp"; diff --git a/src/ecss/mod.rs b/src/ecss/mod.rs index 5f7ddb8..9922129 100644 --- a/src/ecss/mod.rs +++ b/src/ecss/mod.rs @@ -315,11 +315,11 @@ pub trait EcssEnumerationExt: EcssEnumeration + Debug + Copy + Clone + PartialEq #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct GenericEcssEnumWrapper { +pub struct GenericEcssEnumWrapper { field: GenericUnsignedByteField, } -impl GenericEcssEnumWrapper { +impl GenericEcssEnumWrapper { pub const fn ptc() -> PacketTypeCodes { PacketTypeCodes::Enumerated } @@ -331,7 +331,7 @@ impl GenericEcssEnumWrapper { } } -impl UnsignedEnum for GenericEcssEnumWrapper { +impl UnsignedEnum for GenericEcssEnumWrapper { fn size(&self) -> usize { (self.pfc() / 8) as usize } @@ -341,7 +341,7 @@ impl UnsignedEnum for GenericEcssEnumWrapper { } } -impl EcssEnumeration for GenericEcssEnumWrapper { +impl EcssEnumeration for GenericEcssEnumWrapper { fn pfc(&self) -> u8 { size_of::() as u8 * 8_u8 } diff --git a/src/util.rs b/src/util.rs index b944763..88298f4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -207,17 +207,21 @@ impl UnsignedEnum for UnsignedByteField { #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct GenericUnsignedByteField { +pub struct GenericUnsignedByteField { value: TYPE, } -impl GenericUnsignedByteField { +impl GenericUnsignedByteField { pub const fn new(val: TYPE) -> Self { Self { value: val } } + + pub const fn value(&self) -> TYPE { + self.value + } } -impl UnsignedEnum for GenericUnsignedByteField { +impl UnsignedEnum for GenericUnsignedByteField { fn size(&self) -> usize { self.value.written_len() } @@ -344,8 +348,8 @@ pub mod tests { .expect("writing to raw buffer failed"); assert_eq!(len, 1); assert_eq!(buf[0], 5); - for i in 1..8 { - assert_eq!(buf[i], 0); + for val in buf.iter().skip(1) { + assert_eq!(*val, 0); } } @@ -360,8 +364,8 @@ pub mod tests { assert_eq!(len, 2); let raw_val = u16::from_be_bytes(buf[0..2].try_into().unwrap()); assert_eq!(raw_val, 3823); - for i in 2..8 { - assert_eq!(buf[i], 0); + for val in buf.iter().skip(2) { + assert_eq!(*val, 0); } } @@ -376,9 +380,9 @@ pub mod tests { assert_eq!(len, 4); let raw_val = u32::from_be_bytes(buf[0..4].try_into().unwrap()); assert_eq!(raw_val, 80932); - for i in 4..8 { + (4..8).for_each(|i| { assert_eq!(buf[i], 0); - } + }); } #[test] @@ -544,8 +548,8 @@ pub mod tests { .expect("writing to raw buffer failed"); let raw_val = u16::from_be_bytes(buf[0..2].try_into().unwrap()); assert_eq!(raw_val, 3823); - for i in 2..8 { - assert_eq!(buf[i], 0); + for val in buf.iter().skip(2) { + assert_eq!(*val, 0); } }