shadow_crypt_shell/
utils.rs

1use std::io::Read;
2
3use shadow_crypt_core::memory::{SecureBytes, SecureString};
4
5use crate::errors::{WorkflowError, WorkflowResult};
6
7pub fn read_n_bytes_from_file(path: &std::path::Path, n: usize) -> WorkflowResult<SecureBytes> {
8    let f = std::fs::File::open(path)?;
9    let mut buffer = Vec::new();
10    f.take(n as u64).read_to_end(&mut buffer)?;
11
12    Ok(SecureBytes::new(buffer))
13}
14
15pub fn parse_string_from_bytes(bytes: &SecureBytes) -> WorkflowResult<SecureString> {
16    match String::from_utf8(bytes.as_slice().to_vec()) {
17        Ok(s) => Ok(SecureString::new(s)),
18        Err(_) => Err(WorkflowError::Parse(
19            "Failed to decode string from bytes".to_string(),
20        )),
21    }
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27    use std::io::Write;
28    use tempfile::NamedTempFile;
29
30    #[test]
31    fn test_parse_string_from_bytes_valid() {
32        let input_bytes = SecureBytes::new(b"test_filename.txt".to_vec());
33        let result = parse_string_from_bytes(&input_bytes).unwrap();
34        assert_eq!(result.as_str(), "test_filename.txt");
35    }
36
37    #[test]
38    fn test_parse_string_from_bytes_invalid() {
39        let input_bytes = SecureBytes::new(vec![0xff, 0xfe, 0xfd]);
40        let result = parse_string_from_bytes(&input_bytes);
41        assert!(result.is_err());
42        if let Err(WorkflowError::Parse(msg)) = result {
43            assert_eq!(msg, "Failed to decode string from bytes");
44        } else {
45            panic!("Expected Parse error");
46        }
47    }
48
49    #[test]
50    fn test_read_n_bytes_from_file_exact() {
51        let mut temp_file = NamedTempFile::new().unwrap();
52        let data = b"hello world";
53        temp_file.write_all(data).unwrap();
54        let path = temp_file.path();
55
56        let result = read_n_bytes_from_file(path, 11).unwrap();
57        assert_eq!(result.as_slice(), data);
58    }
59
60    #[test]
61    fn test_read_n_bytes_from_file_more_than_available() {
62        let mut temp_file = NamedTempFile::new().unwrap();
63        let data = b"hello";
64        temp_file.write_all(data).unwrap();
65        let path = temp_file.path();
66
67        let result = read_n_bytes_from_file(path, 10).unwrap();
68        assert_eq!(result.as_slice(), data);
69    }
70
71    #[test]
72    fn test_read_n_bytes_from_file_less_than_requested() {
73        let mut temp_file = NamedTempFile::new().unwrap();
74        let data = b"hello world this is a test";
75        temp_file.write_all(data).unwrap();
76        let path = temp_file.path();
77
78        let result = read_n_bytes_from_file(path, 5).unwrap();
79        assert_eq!(result.as_slice(), b"hello");
80    }
81
82    #[test]
83    fn test_read_n_bytes_from_file_zero() {
84        let mut temp_file = NamedTempFile::new().unwrap();
85        let data = b"hello";
86        temp_file.write_all(data).unwrap();
87        let path = temp_file.path();
88
89        let result = read_n_bytes_from_file(path, 0).unwrap();
90        assert_eq!(result.as_slice(), b"");
91    }
92
93    #[test]
94    fn test_read_n_bytes_from_file_nonexistent() {
95        let path = std::path::Path::new("/nonexistent/file");
96        let result = read_n_bytes_from_file(path, 10);
97        assert!(result.is_err());
98        // Should be Io error
99        assert!(matches!(result, Err(WorkflowError::Io(_))));
100    }
101}