Coverage Update #47

Merged
muellerr merged 35 commits from coverage-update into main 2023-12-06 18:05:57 +01:00
6 changed files with 120 additions and 53 deletions
Showing only changes of commit c21ddf3cf0 - Show all commits

View File

@ -13,7 +13,7 @@ def generate_cov_report(open_report: bool, format: str):
os.environ["RUSTFLAGS"] = "-Cinstrument-coverage" os.environ["RUSTFLAGS"] = "-Cinstrument-coverage"
os.environ["LLVM_PROFILE_FILE"] = "target/coverage/%p-%m.profraw" os.environ["LLVM_PROFILE_FILE"] = "target/coverage/%p-%m.profraw"
_LOGGER.info("Executing tests with coverage") _LOGGER.info("Executing tests with coverage")
os.system("cargo test") os.system("cargo test --all-features")
out_path = "./target/debug/coverage" out_path = "./target/debug/coverage"
if format == "lcov": if format == "lcov":

View File

@ -355,9 +355,20 @@ struct FilestoreTlvBase<'first_name, 'second_name> {
pub second_name: Option<Lv<'second_name>>, pub second_name: Option<Lv<'second_name>>,
} }
impl FilestoreTlvBase<'_, '_> {
fn base_len_value(&self) -> usize {
let mut len = 1 + self.first_name.len_full();
if let Some(second_name) = self.second_name {
len += second_name.len_full();
}
len
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FilestoreRequestTlv<'first_name, 'second_name> { pub struct FilestoreRequestTlv<'first_name, 'second_name> {
#[cfg_attr(feature = "serde", serde(borrow))]
base: FilestoreTlvBase<'first_name, 'second_name>, base: FilestoreTlvBase<'first_name, 'second_name>,
} }
@ -467,11 +478,7 @@ impl<'first_name, 'second_name> FilestoreRequestTlv<'first_name, 'second_name> {
} }
pub fn len_value(&self) -> usize { pub fn len_value(&self) -> usize {
let mut len = 1 + self.base.first_name.len_full(); self.base.base_len_value()
if let Some(second_name) = self.base.second_name {
len += second_name.len_full();
}
len
} }
pub fn len_full(&self) -> usize { pub fn len_full(&self) -> usize {
@ -554,8 +561,10 @@ impl GenericTlv for FilestoreRequestTlv<'_, '_> {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct FilestoreResponseTlv<'first_name, 'second_name, 'fs_msg> { pub struct FilestoreResponseTlv<'first_name, 'second_name, 'fs_msg> {
#[cfg_attr(feature = "serde", serde(borrow))]
base: FilestoreTlvBase<'first_name, 'second_name>, base: FilestoreTlvBase<'first_name, 'second_name>,
status_code: u8, status_code: u8,
#[cfg_attr(feature = "serde", serde(borrow))]
filestore_message: Lv<'fs_msg>, filestore_message: Lv<'fs_msg>,
} }
@ -634,12 +643,7 @@ impl<'first_name, 'second_name, 'fs_msg> FilestoreResponseTlv<'first_name, 'seco
} }
pub fn len_value(&self) -> usize { pub fn len_value(&self) -> usize {
let mut len = 1 + self.base.first_name.len_full(); self.base.base_len_value() + self.filestore_message.len_full()
if let Some(second_name) = self.base.second_name {
len += second_name.len_full();
}
len += self.filestore_message.len_full();
len
} }
pub fn len_full(&self) -> usize { pub fn len_full(&self) -> usize {
@ -948,6 +952,7 @@ mod tests {
assert!(tlv.is_ok()); assert!(tlv.is_ok());
let tlv = tlv.unwrap(); let tlv = tlv.unwrap();
assert_eq!(tlv.tlv_type_field(), TlvTypeField::Custom(3)); assert_eq!(tlv.tlv_type_field(), TlvTypeField::Custom(3));
assert!(!tlv.is_standard_tlv());
assert_eq!(tlv.value().len(), 1); assert_eq!(tlv.value().len(), 1);
assert_eq!(tlv.len_full(), 3); assert_eq!(tlv.len_full(), 3);
} }
@ -1006,7 +1011,12 @@ mod tests {
fs_request.len_value(), fs_request.len_value(),
1 + first_name.len_full() + second_name.len_full() 1 + first_name.len_full() + second_name.len_full()
); );
assert_eq!(
fs_request.tlv_type_field(),
TlvTypeField::Standard(TlvType::FilestoreRequest)
);
assert_eq!(fs_request.len_full(), fs_request.len_value() + 2); assert_eq!(fs_request.len_full(), fs_request.len_value() + 2);
assert_eq!(fs_request.len_written(), fs_request.len_full());
assert_eq!(fs_request.action_code(), action_code); assert_eq!(fs_request.action_code(), action_code);
assert_eq!(fs_request.first_name(), first_name); assert_eq!(fs_request.first_name(), first_name);
assert!(fs_request.second_name().is_some()); assert!(fs_request.second_name().is_some());
@ -1138,7 +1148,7 @@ mod tests {
} }
#[test] #[test]
fn test_fs_response_state() { fn test_fs_response_state_one_path() {
let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap(); let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
let response = FilestoreResponseTlv::new_no_filestore_message( let response = FilestoreResponseTlv::new_no_filestore_message(
FilestoreActionCode::CreateFile, FilestoreActionCode::CreateFile,
@ -1148,9 +1158,31 @@ mod tests {
) )
.expect("creating response failed"); .expect("creating response failed");
assert_eq!(response.status_code(), 0b0001); assert_eq!(response.status_code(), 0b0001);
assert_eq!(response.action_code(), FilestoreActionCode::CreateFile);
assert_eq!(response.first_name(), lv_0); assert_eq!(response.first_name(), lv_0);
assert!(response.second_name().is_none()); assert!(response.second_name().is_none());
} }
#[test]
fn test_fs_response_state_two_paths() {
let lv_0 = Lv::new_from_str(TLV_TEST_STR_0).unwrap();
let lv_1 = Lv::new_from_str(TLV_TEST_STR_1).unwrap();
let response = FilestoreResponseTlv::new_no_filestore_message(
FilestoreActionCode::RenameFile,
0b0001,
lv_0,
Some(lv_1),
)
.expect("creating response failed");
assert_eq!(response.status_code(), 0b0001);
assert_eq!(response.action_code(), FilestoreActionCode::RenameFile);
assert_eq!(response.first_name(), lv_0);
assert!(response.second_name().is_some());
assert!(response.second_name().unwrap() == lv_1);
assert_eq!(
response.len_full(),
2 + 1 + lv_0.len_full() + lv_1.len_full() + 1
);
}
#[test] #[test]
fn test_fs_response_serialization() { fn test_fs_response_serialization() {

View File

@ -171,7 +171,7 @@ impl Display for PusError {
write!(f, "crc16 was not calculated") write!(f, "crc16 was not calculated")
} }
PusError::ByteConversion(e) => { PusError::ByteConversion(e) => {
write!(f, "low level byte conversion error: {e}") write!(f, "pus error: {e}")
} }
} }
} }

View File

@ -873,6 +873,8 @@ impl PartialEq<PusTcReader<'_>> for PusTcCreator<'_> {
#[cfg(all(test, feature = "std"))] #[cfg(all(test, feature = "std"))]
mod tests { mod tests {
use std::error::Error;
use super::*; use super::*;
use crate::ecss::PusVersion::PusC; use crate::ecss::PusVersion::PusC;
use crate::ecss::{PusError, PusPacket, WritablePusPacket}; use crate::ecss::{PusError, PusPacket, WritablePusPacket};
@ -1062,16 +1064,21 @@ mod tests {
let res = pus_tc.write_to_bytes(test_buf.as_mut_slice()); let res = pus_tc.write_to_bytes(test_buf.as_mut_slice());
assert!(res.is_err()); assert!(res.is_err());
let err = res.unwrap_err(); let err = res.unwrap_err();
match err { if let PusError::ByteConversion(e) = err {
PusError::ByteConversion(err) => { assert_eq!(
if let ByteConversionError::ToSliceTooSmall { found, expected } = err { e,
assert_eq!(expected, pus_tc.len_written()); ByteConversionError::ToSliceTooSmall {
assert_eq!(found, 12); found: 12,
} else { expected: 13
panic!("Unexpected error")
} }
} );
_ => panic!("Unexpected error"), assert_eq!(
err.to_string(),
"pus error: target slice with size 12 is too small, expected size of at least 13"
);
assert_eq!(err.source().unwrap().to_string(), e.to_string());
} else {
panic!("unexpected error {err}");
} }
} }

View File

@ -408,7 +408,9 @@ impl DynCdsTimeProvider for TimeProvider<DaysLen24Bits> {}
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use spacepackets::time::cds::{TimeProvider, LengthOfDaySegment, get_dyn_time_provider_from_bytes}; /// use spacepackets::time::cds::{
/// TimeProvider, LengthOfDaySegment, get_dyn_time_provider_from_bytes, SubmillisPrecision,
/// };
/// use spacepackets::time::{TimeWriter, CcsdsTimeCodes, CcsdsTimeProvider}; /// use spacepackets::time::{TimeWriter, CcsdsTimeCodes, CcsdsTimeProvider};
/// ///
/// let timestamp_now = TimeProvider::new_with_u16_days(24, 24); /// let timestamp_now = TimeProvider::new_with_u16_days(24, 24);
@ -423,7 +425,7 @@ impl DynCdsTimeProvider for TimeProvider<DaysLen24Bits> {}
/// assert_eq!(dyn_provider.len_of_day_seg(), LengthOfDaySegment::Short16Bits); /// assert_eq!(dyn_provider.len_of_day_seg(), LengthOfDaySegment::Short16Bits);
/// assert_eq!(dyn_provider.ccsds_days_as_u32(), 24); /// assert_eq!(dyn_provider.ccsds_days_as_u32(), 24);
/// assert_eq!(dyn_provider.ms_of_day(), 24); /// assert_eq!(dyn_provider.ms_of_day(), 24);
/// assert_eq!(dyn_provider.submillis_precision(), None); /// assert_eq!(dyn_provider.submillis_precision(), SubmillisPrecision::Absent);
/// } /// }
/// ``` /// ```
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
@ -510,7 +512,7 @@ impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
/// using picosecond resolution, but significantly simplifies comparison of timestamps. /// using picosecond resolution, but significantly simplifies comparison of timestamps.
pub fn precision_as_ns(&self) -> Option<u32> { pub fn precision_as_ns(&self) -> Option<u32> {
match self.submillis_precision() { match self.submillis_precision() {
SubmillisPrecision::Microseconds => Some(self.submillis as u32 * 1000), SubmillisPrecision::Microseconds => Some(self.submillis * 1000),
SubmillisPrecision::Picoseconds => Some(self.submillis / 1000), SubmillisPrecision::Picoseconds => Some(self.submillis / 1000),
_ => None, _ => None,
} }
@ -1159,7 +1161,7 @@ impl<ProvidesDaysLen: ProvidesDaysLength> CcsdsTimeProvider for TimeProvider<Pro
let mut ns_since_last_sec = (self.ms_of_day % 1000) * 10_u32.pow(6); let mut ns_since_last_sec = (self.ms_of_day % 1000) * 10_u32.pow(6);
match self.submillis_precision() { match self.submillis_precision() {
SubmillisPrecision::Microseconds => { SubmillisPrecision::Microseconds => {
ns_since_last_sec += self.submillis() as u32 * 1000; ns_since_last_sec += self.submillis() * 1000;
} }
SubmillisPrecision::Picoseconds => { SubmillisPrecision::Picoseconds => {
ns_since_last_sec += self.submillis() / 1000; ns_since_last_sec += self.submillis() / 1000;

View File

@ -94,7 +94,6 @@ pub fn fractional_part_from_subsec_ns(
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum CucError { pub enum CucError {
InvalidCounterWidth(u8), InvalidCounterWidth(u8),
InvalidFractionResolution(FractionalResolution),
/// Invalid counter supplied. /// Invalid counter supplied.
InvalidCounter { InvalidCounter {
width: u8, width: u8,
@ -112,9 +111,6 @@ impl Display for CucError {
CucError::InvalidCounterWidth(w) => { CucError::InvalidCounterWidth(w) => {
write!(f, "invalid cuc counter byte width {w}") write!(f, "invalid cuc counter byte width {w}")
} }
CucError::InvalidFractionResolution(w) => {
write!(f, "invalid cuc fractional part byte width {w:?}")
}
CucError::InvalidCounter { width, counter } => { CucError::InvalidCounter { width, counter } => {
write!(f, "invalid cuc counter {counter} for width {width}") write!(f, "invalid cuc counter {counter} for width {width}")
} }
@ -288,6 +284,8 @@ impl TimeProviderCcsdsEpoch {
.map_err(|e| e.into()) .map_err(|e| e.into())
} }
/// Generates a CUC timestamp from a UNIX timestamp with a width of 4. This width is able
/// to accomodate all possible UNIX timestamp values.
pub fn from_unix_stamp( pub fn from_unix_stamp(
unix_stamp: &UnixTimestamp, unix_stamp: &UnixTimestamp,
res: FractionalResolution, res: FractionalResolution,
@ -299,13 +297,6 @@ impl TimeProviderCcsdsEpoch {
unix_stamp.as_date_time().unwrap(), unix_stamp.as_date_time().unwrap(),
)); ));
} }
if ccsds_epoch > u32::MAX as i64 {
return Err(CucError::InvalidCounter {
width: 4,
counter: ccsds_epoch as u64,
}
.into());
}
let mut fractions = None; let mut fractions = None;
if let Some(subsec_millis) = unix_stamp.subsecond_millis { if let Some(subsec_millis) = unix_stamp.subsecond_millis {
fractions = fractional_part_from_subsec_ns(res, subsec_millis as u64 * 10_u64.pow(6)); fractions = fractional_part_from_subsec_ns(res, subsec_millis as u64 * 10_u64.pow(6));
@ -335,7 +326,6 @@ impl TimeProviderCcsdsEpoch {
} }
pub fn set_fractions(&mut self, fractions: FractionalPart) -> Result<(), CucError> { pub fn set_fractions(&mut self, fractions: FractionalPart) -> Result<(), CucError> {
Self::verify_fractions_width(fractions.0)?;
Self::verify_fractions_value(fractions)?; Self::verify_fractions_value(fractions)?;
self.fractions = Some(fractions); self.fractions = Some(fractions);
self.update_p_field_fractions(); self.update_p_field_fractions();
@ -371,7 +361,6 @@ impl TimeProviderCcsdsEpoch {
}); });
} }
if let Some(fractions) = fractions { if let Some(fractions) = fractions {
Self::verify_fractions_width(fractions.0)?;
Self::verify_fractions_value(fractions)?; Self::verify_fractions_value(fractions)?;
} }
Ok(Self { Ok(Self {
@ -457,13 +446,6 @@ impl TimeProviderCcsdsEpoch {
Ok(()) Ok(())
} }
fn verify_fractions_width(width: FractionalResolution) -> Result<(), CucError> {
if width as u8 > 3 {
return Err(CucError::InvalidFractionResolution(width));
}
Ok(())
}
fn verify_fractions_value(val: FractionalPart) -> Result<(), CucError> { fn verify_fractions_value(val: FractionalPart) -> Result<(), CucError> {
if val.1 > 2u32.pow((val.0 as u32) * 8) - 1 { if val.1 > 2u32.pow((val.0 as u32) * 8) - 1 {
return Err(CucError::InvalidFractions { return Err(CucError::InvalidFractions {
@ -1134,12 +1116,7 @@ mod tests {
assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 2); assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 2);
} }
#[test] fn check_stamp_after_addition(cuc_stamp: &TimeProviderCcsdsEpoch) {
fn add_duration_basic() {
let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200);
cuc_stamp.set_fractional_resolution(FractionalResolution::FifteenUs);
let duration = Duration::from_millis(2500);
cuc_stamp += duration;
assert_eq!(cuc_stamp.width_counter_pair().1, 202); assert_eq!(cuc_stamp.width_counter_pair().1, 202);
let fractions = cuc_stamp.width_fractions_pair().unwrap().1; let fractions = cuc_stamp.width_fractions_pair().unwrap().1;
let expected_val = let expected_val =
@ -1152,6 +1129,41 @@ mod tests {
assert!(cuc_stamp2.subsecond_millis().unwrap() <= 1); assert!(cuc_stamp2.subsecond_millis().unwrap() <= 1);
} }
#[test]
fn add_duration_basic() {
let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200);
cuc_stamp.set_fractional_resolution(FractionalResolution::FifteenUs);
let duration = Duration::from_millis(2500);
cuc_stamp += duration;
check_stamp_after_addition(&cuc_stamp);
}
#[test]
fn add_duration_basic_on_ref() {
let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200);
cuc_stamp.set_fractional_resolution(FractionalResolution::FifteenUs);
let duration = Duration::from_millis(2500);
let new_stamp = cuc_stamp + duration;
check_stamp_after_addition(&new_stamp);
}
#[test]
fn add_duration_basic_no_fractions() {
let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200);
let duration = Duration::from_millis(2000);
cuc_stamp += duration;
assert_eq!(cuc_stamp.counter(), 202);
assert_eq!(cuc_stamp.width_fractions_pair(), None);
}
#[test]
fn add_duration_basic_on_ref_no_fractions() {
let cuc_stamp = TimeProviderCcsdsEpoch::new(200);
let duration = Duration::from_millis(2000);
let new_stamp = cuc_stamp + duration;
assert_eq!(new_stamp.counter(), 202);
assert_eq!(new_stamp.width_fractions_pair(), None);
}
#[test] #[test]
fn add_duration_overflow() { fn add_duration_overflow() {
let mut cuc_stamp = let mut cuc_stamp =
@ -1200,4 +1212,18 @@ mod tests {
(-DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32) as u32 (-DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32) as u32
); );
} }
#[test]
fn test_invalid_counter() {
let cuc_error = TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(1, 256), None);
assert!(cuc_error.is_err());
let cuc_error = cuc_error.unwrap_err();
if let CucError::InvalidCounter { width, counter } = cuc_error {
assert_eq!(width, 1);
assert_eq!(counter, 256);
assert_eq!(cuc_error.to_string(), "invalid cuc counter 256 for width 1");
} else {
panic!("unexpected error: {}", cuc_error);
}
}
} }