container_device_interface/
utils.rs

1use std::{
2    ffi::OsStr,
3    fs::rename,
4    io::{Error, ErrorKind},
5    path::Path,
6};
7
8use anyhow::Result;
9
10pub fn merge<T>(v1: &mut Option<Vec<T>>, v2: &Option<Vec<T>>) -> Option<Vec<T>>
11where
12    T: Clone,
13{
14    let mut result = v1.clone().map(|mut vec| {
15        if let Some(ref other) = v2 {
16            vec.extend(other.iter().cloned());
17        }
18        vec
19    });
20
21    if result.is_none() {
22        result.clone_from(v2);
23    }
24
25    result
26}
27
28// rename src to dst, both relative to the directory dir. If dst already exists
29// refuse renaming with an error unless overwrite is explicitly asked for.
30pub fn rename_in<P: AsRef<Path>, Q: AsRef<Path>>(
31    dir: P,
32    src: Q,
33    dst: Q,
34    overwrite: bool,
35) -> Result<()> {
36    let src_path = dir.as_ref().join(src);
37    let dst_path = dir.as_ref().join(dst);
38
39    if !overwrite && dst_path.exists() {
40        return Err(Error::new(ErrorKind::AlreadyExists, "destination already exists").into());
41    }
42
43    rename(src_path, &dst_path)?;
44
45    Ok(())
46}
47
48pub fn is_cdi_spec(path: &Path) -> bool {
49    path.extension()
50        .and_then(OsStr::to_str)
51        .map(|ext| ext.eq_ignore_ascii_case("json") || ext.eq_ignore_ascii_case("yaml"))
52        .unwrap_or(false)
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use std::fs::{self, File};
59    use std::io::Write;
60    use std::path::Path;
61    use tempfile::TempDir;
62
63    #[test]
64    fn test_merge_none_none() {
65        let mut v1: Option<Vec<i32>> = None;
66        let v2: Option<Vec<i32>> = None;
67
68        let result = merge(&mut v1, &v2);
69        assert!(result.is_none());
70    }
71
72    #[test]
73    fn test_merge_some_none() {
74        let mut v1 = Some(vec![1, 2, 3]);
75        let v2: Option<Vec<i32>> = None;
76
77        let result = merge(&mut v1, &v2);
78        assert_eq!(result, Some(vec![1, 2, 3]));
79    }
80
81    #[test]
82    fn test_merge_none_some() {
83        let mut v1: Option<Vec<i32>> = None;
84        let v2 = Some(vec![4, 5, 6]);
85
86        let result = merge(&mut v1, &v2);
87        assert_eq!(result, Some(vec![4, 5, 6]));
88    }
89
90    #[test]
91    fn test_merge_some_some() {
92        let mut v1 = Some(vec![1, 2, 3]);
93        let v2 = Some(vec![4, 5, 6]);
94
95        let result = merge(&mut v1, &v2);
96        assert_eq!(result, Some(vec![1, 2, 3, 4, 5, 6]));
97    }
98
99    #[test]
100    fn test_rename_in_success() {
101        let tmp_dir = TempDir::new().unwrap();
102        let dir_path = tmp_dir.path().to_path_buf();
103        let mut src_file = File::create(dir_path.join("src.txt")).unwrap();
104        let dst_file = dir_path.join("dst.txt");
105
106        let _ = src_file.write_all(b"Hello, CDI-rs!");
107
108        rename_in(&dir_path, "src.txt", "dst.txt", false).unwrap();
109        assert!(dst_file.exists());
110        assert!(!Path::new(&dir_path).join("src.txt").exists());
111    }
112
113    #[test]
114    fn test_rename_in_overwrite() {
115        let tmp_dir = TempDir::new().unwrap();
116        let dir_path = tmp_dir.path().to_path_buf();
117
118        let mut src_file = File::create(dir_path.join("src.txt")).unwrap();
119        let mut dst_file = File::create(dir_path.join("dst.txt")).unwrap();
120
121        let _ = src_file.write_all(b"Hello, CDI-rs!");
122        let _ = dst_file.write_all(b"Goodbye, CDI-rs!");
123
124        rename_in(&dir_path, "src.txt", "dst.txt", true).unwrap();
125        assert_eq!(
126            fs::read_to_string(dir_path.join("dst.txt")).unwrap(),
127            "Hello, CDI-rs!"
128        );
129        assert!(!Path::new(&dir_path).join("src.txt").exists());
130    }
131
132    #[test]
133    fn test_rename_in_no_overwrite() {
134        let tmp_dir = TempDir::new().unwrap();
135        let dir_path = tmp_dir.path().to_path_buf();
136
137        let mut src_file = File::create(dir_path.join("src.txt")).unwrap();
138        let mut dst_file = File::create(dir_path.join("dst.txt")).unwrap();
139
140        let _ = src_file.write_all(b"Hello, CDI-rs!");
141        let _ = dst_file.write_all(b"Goodbye, CDI-rs!");
142
143        let result = rename_in(&dir_path, "src.txt", "dst.txt", false);
144        assert!(result.is_err());
145        assert!(Path::new(&dir_path).join("src.txt").exists());
146        assert!(Path::new(&dir_path).join("dst.txt").exists());
147    }
148}