diff --git a/src/cfdp/pdu/metadata.rs b/src/cfdp/pdu/metadata.rs index 646d03b..920c63c 100644 --- a/src/cfdp/pdu/metadata.rs +++ b/src/cfdp/pdu/metadata.rs @@ -343,7 +343,6 @@ pub mod tests { use alloc::string::ToString; use crate::cfdp::lv::Lv; - use crate::cfdp::pdu::eof::EofPdu; use crate::cfdp::pdu::metadata::{ build_metadata_opts_from_slice, build_metadata_opts_from_vec, MetadataGenericParams, MetadataPduCreator, MetadataPduReader, diff --git a/src/time/cds.rs b/src/time/cds.rs index 85c7f65..65e9ea3 100644 --- a/src/time/cds.rs +++ b/src/time/cds.rs @@ -1307,6 +1307,7 @@ mod tests { use super::*; use crate::time::TimestampError::{ByteConversion, InvalidTimeCode}; use crate::ByteConversionError::{FromSliceTooSmall, ToSliceTooSmall}; + use alloc::string::ToString; use chrono::{Datelike, NaiveDate, Timelike}; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; @@ -1415,6 +1416,11 @@ mod tests { fn test_write() { let mut buf = [0; 16]; let time_stamper_0 = TimeProvider::new_with_u16_days(0, 0); + let unix_stamp = time_stamper_0.unix_stamp(); + assert_eq!( + unix_stamp.unix_seconds, + (DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32).into() + ); let mut res = time_stamper_0.write_to_bytes(&mut buf); assert!(res.is_ok()); assert_eq!(buf[0], (CcsdsTimeCodes::Cds as u8) << 4); @@ -1447,10 +1453,15 @@ mod tests { for i in 0..6 { let res = time_stamper.write_to_bytes(&mut buf[0..i]); assert!(res.is_err()); - match res.unwrap_err() { + let error = res.unwrap_err(); + match error { ByteConversion(ToSliceTooSmall { found, expected }) => { assert_eq!(found, i); assert_eq!(expected, 7); + assert_eq!( + error.to_string(), + "time stamp: target slice with size 0 is too small, expected size of at least 7" + ); } _ => panic!( "{}", @@ -1492,12 +1503,13 @@ mod tests { let res = TimeProvider::::from_bytes(&buf); assert!(res.is_err()); let err = res.unwrap_err(); - match err { - InvalidTimeCode { expected, found } => { - assert_eq!(expected, CcsdsTimeCodes::Cds); - assert_eq!(found, 0); - } - _ => {} + if let InvalidTimeCode { expected, found } = err { + assert_eq!(expected, CcsdsTimeCodes::Cds); + assert_eq!(found, 0); + assert_eq!( + err.to_string(), + "invalid raw time code value 0 for time code Cds" + ); } } @@ -1942,7 +1954,7 @@ mod tests { let invalid_unix_secs: i64 = (u16::MAX as i64 + 1) * SECONDS_PER_DAY as i64; let subsec_millis = 0; match TimeProvider::from_unix_secs_with_u16_days(&UnixTimestamp::const_new( - invalid_unix_secs as i64, + invalid_unix_secs, subsec_millis, )) { Ok(_) => { @@ -1954,6 +1966,7 @@ mod tests { days, unix_to_ccsds_days(invalid_unix_secs / SECONDS_PER_DAY as i64) ); + assert_eq!(e.to_string(), "cds error: invalid ccsds days 69919"); } else { panic!("unexpected error {}", e) } diff --git a/src/time/cuc.rs b/src/time/cuc.rs index 252faea..817578d 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -7,6 +7,7 @@ use chrono::Datelike; use core::fmt::Debug; use core::ops::{Add, AddAssign}; use core::time::Duration; +use core::u64; const MIN_CUC_LEN: usize = 2; @@ -95,8 +96,14 @@ pub enum CucError { InvalidCounterWidth(u8), InvalidFractionResolution(FractionalResolution), /// Invalid counter supplied. - InvalidCounter(u8, u64), - InvalidFractions(FractionalResolution, u64), + InvalidCounter { + width: u8, + counter: u64, + }, + InvalidFractions { + resolution: FractionalResolution, + value: u64, + }, } impl Display for CucError { @@ -108,11 +115,14 @@ impl Display for CucError { CucError::InvalidFractionResolution(w) => { write!(f, "invalid cuc fractional part byte width {w:?}") } - CucError::InvalidCounter(w, c) => { - write!(f, "invalid cuc counter {c} for width {w}") + CucError::InvalidCounter { width, counter } => { + write!(f, "invalid cuc counter {counter} for width {width}") } - CucError::InvalidFractions(w, c) => { - write!(f, "invalid cuc fractional part {c} for width {w:?}") + CucError::InvalidFractions { resolution, value } => { + write!( + f, + "invalid cuc fractional part {value} for resolution {resolution:?}" + ) } } } @@ -290,7 +300,11 @@ impl TimeProviderCcsdsEpoch { )); } if ccsds_epoch > u32::MAX as i64 { - return Err(CucError::InvalidCounter(4, ccsds_epoch as u64).into()); + return Err(CucError::InvalidCounter { + width: 4, + counter: ccsds_epoch as u64, + } + .into()); } let mut fractions = None; if let Some(subsec_millis) = unix_stamp.subsecond_millis { @@ -343,7 +357,10 @@ impl TimeProviderCcsdsEpoch { ) -> Result { Self::verify_counter_width(counter.0)?; if counter.1 > (2u64.pow(counter.0 as u32 * 8) - 1) as u32 { - return Err(CucError::InvalidCounter(counter.0, counter.1 as u64)); + return Err(CucError::InvalidCounter { + width: counter.0, + counter: counter.1 as u64, + }); } if let Some(fractions) = fractions { Self::verify_fractions_width(fractions.0)?; @@ -441,7 +458,10 @@ impl TimeProviderCcsdsEpoch { fn verify_fractions_value(val: FractionalPart) -> Result<(), CucError> { if val.1 > 2u32.pow((val.0 as u32) * 8) - 1 { - return Err(CucError::InvalidFractions(val.0, val.1 as u64)); + return Err(CucError::InvalidFractions { + resolution: val.0, + value: val.1 as u64, + }); } Ok(()) } @@ -713,6 +733,7 @@ impl Add for &TimeProviderCcsdsEpoch { #[cfg(test)] mod tests { use super::*; + use alloc::string::ToString; use chrono::{Datelike, Timelike}; #[allow(unused_imports)] use std::println; @@ -861,6 +882,7 @@ mod tests { #[test] fn invalid_buf_len_for_read() {} + #[test] fn write_read_three_byte_cntr_stamp() { let mut buf = [0; 4]; @@ -1128,4 +1150,17 @@ mod tests { cuc_stamp += duration; assert_eq!(cuc_stamp.counter.1, 10); } + + #[test] + fn test_invalid_width_param() { + let error = TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(8, 0), None); + assert!(error.is_err()); + let error = error.unwrap_err(); + if let CucError::InvalidCounterWidth(width) = error { + assert_eq!(width, 8); + assert_eq!(error.to_string(), "invalid cuc counter byte width 8"); + } else { + panic!("unexpected error: {}", error); + } + } } diff --git a/src/time/mod.rs b/src/time/mod.rs index 5dedf99..3376677 100644 --- a/src/time/mod.rs +++ b/src/time/mod.rs @@ -82,13 +82,13 @@ impl Display for TimestampError { ) } TimestampError::Cds(e) => { - write!(f, "cds error {e}") + write!(f, "cds error: {e}") } TimestampError::Cuc(e) => { - write!(f, "cuc error {e}") + write!(f, "cuc error: {e}") } TimestampError::ByteConversion(e) => { - write!(f, "byte conversion error {e}") + write!(f, "time stamp: {e}") } TimestampError::DateBeforeCcsdsEpoch(e) => { write!(f, "datetime with date before ccsds epoch: {e}") @@ -412,7 +412,11 @@ impl Add for &UnixTimestamp { #[cfg(all(test, feature = "std"))] mod tests { - use super::*; + use alloc::string::ToString; + use chrono::{Datelike, Timelike}; + use std::format; + + use super::{cuc::CucError, *}; #[test] fn test_days_conversion() { @@ -426,6 +430,14 @@ mod tests { assert!(sec_floats > 0.0); } + #[test] + fn test_ms_of_day() { + let ms = ms_of_day(0.0); + assert_eq!(ms, 0); + let ms = ms_of_day(5.0); + assert_eq!(ms, 5000); + } + #[test] fn test_ccsds_epoch() { let now = SystemTime::now() @@ -534,6 +546,25 @@ mod tests { assert!(stamp1.subsecond_millis().is_none()); } + #[test] + fn test_as_dt() { + let stamp = UnixTimestamp::new_only_seconds(0); + let dt = stamp.as_date_time().unwrap(); + assert_eq!(dt.year(), 1970); + assert_eq!(dt.month(), 1); + assert_eq!(dt.day(), 1); + assert_eq!(dt.hour(), 0); + assert_eq!(dt.minute(), 0); + assert_eq!(dt.second(), 0); + } + + #[test] + fn test_from_now() { + let stamp_now = UnixTimestamp::from_now().unwrap(); + let dt_now = stamp_now.as_date_time().unwrap(); + assert!(dt_now.year() >= 2020); + } + #[test] fn test_addition_spillover() { let mut stamp0 = UnixTimestamp::new(1, 900).unwrap(); @@ -544,4 +575,11 @@ mod tests { assert_eq!(stamp0.unix_seconds, 3); assert_eq!(stamp0.subsecond_millis().unwrap(), 100); } + + #[test] + fn test_cuc_error_printout() { + let cuc_error = CucError::InvalidCounterWidth(12); + let stamp_error = TimestampError::from(cuc_error); + assert_eq!(stamp_error.to_string(), format!("cuc error: {cuc_error}")); + } }