Coverage Update #47
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,13 @@ impl<'data> Tlv<'data> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_with_custom_type(tlv_type: u8, data: &[u8]) -> Result<Tlv, TlvLvError> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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<TYPE> {
|
||||
pub struct GenericEcssEnumWrapper<TYPE: Copy> {
|
||||
field: GenericUnsignedByteField<TYPE>,
|
||||
}
|
||||
|
||||
impl<TYPE> GenericEcssEnumWrapper<TYPE> {
|
||||
impl<TYPE: Copy> GenericEcssEnumWrapper<TYPE> {
|
||||
pub const fn ptc() -> PacketTypeCodes {
|
||||
PacketTypeCodes::Enumerated
|
||||
}
|
||||
@ -331,7 +331,7 @@ impl<TYPE> GenericEcssEnumWrapper<TYPE> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TYPE: ToBeBytes> UnsignedEnum for GenericEcssEnumWrapper<TYPE> {
|
||||
impl<TYPE: Copy + ToBeBytes> UnsignedEnum for GenericEcssEnumWrapper<TYPE> {
|
||||
fn size(&self) -> usize {
|
||||
(self.pfc() / 8) as usize
|
||||
}
|
||||
@ -341,7 +341,7 @@ impl<TYPE: ToBeBytes> UnsignedEnum for GenericEcssEnumWrapper<TYPE> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TYPE: ToBeBytes> EcssEnumeration for GenericEcssEnumWrapper<TYPE> {
|
||||
impl<TYPE: Copy + ToBeBytes> EcssEnumeration for GenericEcssEnumWrapper<TYPE> {
|
||||
fn pfc(&self) -> u8 {
|
||||
size_of::<TYPE>() as u8 * 8_u8
|
||||
}
|
||||
|
26
src/util.rs
26
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<TYPE> {
|
||||
pub struct GenericUnsignedByteField<TYPE: Copy> {
|
||||
value: TYPE,
|
||||
}
|
||||
|
||||
impl<TYPE> GenericUnsignedByteField<TYPE> {
|
||||
impl<TYPE: Copy> GenericUnsignedByteField<TYPE> {
|
||||
pub const fn new(val: TYPE) -> Self {
|
||||
Self { value: val }
|
||||
}
|
||||
|
||||
pub const fn value(&self) -> TYPE {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<TYPE: ToBeBytes> UnsignedEnum for GenericUnsignedByteField<TYPE> {
|
||||
impl<TYPE: Copy + ToBeBytes> UnsignedEnum for GenericUnsignedByteField<TYPE> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user