From a313a784ffcd613553641c5ad958d72568f0832c Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 2 Jul 2023 17:18:33 +0200 Subject: [PATCH] finish FS request unittests --- src/cfdp/lv.rs | 8 ++++ src/cfdp/tlv.rs | 108 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/cfdp/lv.rs b/src/cfdp/lv.rs index 23701be..cf6f209 100644 --- a/src/cfdp/lv.rs +++ b/src/cfdp/lv.rs @@ -1,6 +1,7 @@ //! Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8. use crate::cfdp::TlvLvError; use crate::{ByteConversionError, SizeMissmatch}; +use core::str::Utf8Error; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] @@ -95,6 +96,13 @@ impl<'data> Lv<'data> { self.data } + /// Convenience function to extract the value as a [str]. This is useful if the LV is + /// known to contain a [str], for example being a file name. + pub fn value_as_str(&self) -> Option> { + self.data?; + Some(std::str::from_utf8(self.data.unwrap())) + } + /// Writes the LV to a raw buffer. Please note that the first byte will contain the length /// of the value, but the values may not exceed a length of [u8::MAX]. pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { diff --git a/src/cfdp/tlv.rs b/src/cfdp/tlv.rs index 981f6e0..2bb3e9d 100644 --- a/src/cfdp/tlv.rs +++ b/src/cfdp/tlv.rs @@ -398,7 +398,7 @@ impl<'first_name, 'second_name> FilestoreRequestTlv<'first_name, 'second_name> { buf[0] = TlvType::FilestoreRequest as u8; buf[1] = self.len_value() as u8; buf[2] = (self.action_code as u8) << 4; - let mut current_idx = 2; + let mut current_idx = 3; // Length checks were already performed. self.first_name.write_to_be_bytes_no_len_check( &mut buf[current_idx..current_idx + self.first_name.len_full()], @@ -428,6 +428,7 @@ impl<'first_name, 'second_name> FilestoreRequestTlv<'first_name, 'second_name> { let mut current_idx = 2; let action_code = FilestoreActionCode::try_from((buf[2] >> 4) & 0b1111) .map_err(|_| TlvLvError::InvalidFilestoreActionCode((buf[2] >> 4) & 0b1111))?; + current_idx += 1; let first_name = Lv::from_bytes(&buf[current_idx..])?; let mut second_name = None; @@ -453,6 +454,9 @@ mod tests { use crate::cfdp::TlvLvError; use crate::util::{UbfU8, UnsignedEnum}; + const TLV_TEST_STR_0: &'static str = "hello.txt"; + const TLV_TEST_STR_1: &'static str = "hello2.txt"; + #[test] fn test_basic() { let entity_id = UbfU8::new(5); @@ -574,9 +578,11 @@ mod tests { assert_eq!(tlv.len_full(), 3); } - fn generic_fs_request_test_one_file(action_code: FilestoreActionCode) { + fn generic_fs_request_test_one_file( + action_code: FilestoreActionCode, + ) -> FilestoreRequestTlv<'static, 'static> { assert!(!FilestoreRequestTlv::has_second_filename(action_code)); - let first_name = Lv::new_from_str("hello.txt").unwrap(); + let first_name = Lv::new_from_str(TLV_TEST_STR_0).unwrap(); let fs_request = match action_code { FilestoreActionCode::CreateFile => FilestoreRequestTlv::new_create_file(first_name), FilestoreActionCode::DeleteFile => FilestoreRequestTlv::new_delete_file(first_name), @@ -599,12 +605,15 @@ mod tests { assert_eq!(fs_request.action_code(), action_code); assert_eq!(fs_request.first_name(), first_name); assert_eq!(fs_request.second_name(), None); + fs_request } - fn generic_fs_request_test_two_files(action_code: FilestoreActionCode) { + fn generic_fs_request_test_two_files( + action_code: FilestoreActionCode, + ) -> FilestoreRequestTlv<'static, 'static> { assert!(FilestoreRequestTlv::has_second_filename(action_code)); - let first_name = Lv::new_from_str("hello.txt").unwrap(); - let second_name = Lv::new_from_str("hello2.txt").unwrap(); + let first_name = Lv::new_from_str(TLV_TEST_STR_0).unwrap(); + let second_name = Lv::new_from_str(TLV_TEST_STR_1).unwrap(); let fs_request = match action_code { FilestoreActionCode::ReplaceFile => { FilestoreRequestTlv::new_replace_file(first_name, second_name) @@ -628,44 +637,129 @@ mod tests { assert_eq!(fs_request.first_name(), first_name); assert!(fs_request.second_name().is_some()); assert_eq!(fs_request.second_name().unwrap(), second_name); + fs_request } #[test] fn test_fs_request_basic_create_file() { generic_fs_request_test_one_file(FilestoreActionCode::CreateFile); } + #[test] fn test_fs_request_basic_delete() { generic_fs_request_test_one_file(FilestoreActionCode::DeleteFile); } + #[test] fn test_fs_request_basic_create_dir() { generic_fs_request_test_one_file(FilestoreActionCode::CreateDirectory); } + #[test] fn test_fs_request_basic_remove_dir() { generic_fs_request_test_one_file(FilestoreActionCode::RemoveDirectory); } + #[test] fn test_fs_request_basic_deny_file() { generic_fs_request_test_one_file(FilestoreActionCode::DenyFile); } + #[test] fn test_fs_request_basic_deny_dir() { generic_fs_request_test_one_file(FilestoreActionCode::DenyDirectory); } + #[test] fn test_fs_request_basic_append_file() { generic_fs_request_test_two_files(FilestoreActionCode::AppendFile); } + #[test] fn test_fs_request_basic_rename_file() { generic_fs_request_test_two_files(FilestoreActionCode::RenameFile); } + #[test] fn test_fs_request_basic_replace_file() { generic_fs_request_test_two_files(FilestoreActionCode::ReplaceFile); } + + fn check_fs_request_first_part( + buf: &[u8], + action_code: FilestoreActionCode, + expected_val_len: u8, + ) -> usize { + assert_eq!(buf[0], TlvType::FilestoreRequest as u8); + assert_eq!(buf[1], expected_val_len); + assert_eq!((buf[2] >> 4) & 0b1111, action_code as u8); + let lv = Lv::from_bytes(&buf[3..]); + assert!(lv.is_ok()); + let lv = lv.unwrap(); + assert_eq!(lv.value_as_str().unwrap().unwrap(), TLV_TEST_STR_0); + 3 + lv.len_full() + } + #[test] - fn test_fs_request_serialization() {} + fn test_fs_request_serialization_one_file() { + let req = generic_fs_request_test_one_file(FilestoreActionCode::CreateFile); + let mut buf: [u8; 64] = [0; 64]; + let res = req.write_to_bytes(&mut buf); + assert!(res.is_ok()); + let written = res.unwrap(); + assert_eq!(written, 3 + 1 + TLV_TEST_STR_0.len()); + assert_eq!(written, req.len_full()); + check_fs_request_first_part( + &buf, + FilestoreActionCode::CreateFile, + 1 + 1 + TLV_TEST_STR_0.len() as u8, + ); + } + + #[test] + fn test_fs_request_deserialization_one_file() { + let req = generic_fs_request_test_one_file(FilestoreActionCode::CreateFile); + let mut buf: [u8; 64] = [0; 64]; + let res = req.write_to_bytes(&mut buf); + assert!(res.is_ok()); + let req_conv_back = FilestoreRequestTlv::from_bytes(&buf); + assert!(req_conv_back.is_ok()); + let req_conv_back = req_conv_back.unwrap(); + assert_eq!(req_conv_back, req); + } + + #[test] + fn test_fs_request_serialization_two_files() { + let req = generic_fs_request_test_two_files(FilestoreActionCode::RenameFile); + let mut buf: [u8; 64] = [0; 64]; + let res = req.write_to_bytes(&mut buf); + assert!(res.is_ok()); + let written = res.unwrap(); + assert_eq!(written, req.len_full()); + assert_eq!( + written, + 3 + 1 + TLV_TEST_STR_0.len() + 1 + TLV_TEST_STR_1.len() + ); + let current_idx = check_fs_request_first_part( + &buf, + FilestoreActionCode::RenameFile, + 1 + 1 + TLV_TEST_STR_0.len() as u8 + 1 + TLV_TEST_STR_1.len() as u8, + ); + let second_lv = Lv::from_bytes(&buf[current_idx..]); + assert!(second_lv.is_ok()); + let second_lv = second_lv.unwrap(); + assert_eq!(second_lv.value_as_str().unwrap().unwrap(), TLV_TEST_STR_1); + assert_eq!(current_idx + second_lv.len_full(), req.len_full()); + } + + #[test] + fn test_fs_request_deserialization_two_files() { + let req = generic_fs_request_test_two_files(FilestoreActionCode::RenameFile); + let mut buf: [u8; 64] = [0; 64]; + req.write_to_bytes(&mut buf).unwrap(); + let req_conv_back = FilestoreRequestTlv::from_bytes(&buf); + assert!(req_conv_back.is_ok()); + let req_conv_back = req_conv_back.unwrap(); + assert_eq!(req_conv_back, req); + } }