container_device_interface/
utils.rs1use 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
28pub 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}