1mod azdls;
34mod gcs;
35mod oss;
36mod s3;
37
38use std::collections::HashMap;
39
40pub use azdls::*;
41pub use gcs::*;
42pub use oss::*;
43pub use s3::*;
44use serde::{Deserialize, Serialize};
45
46#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
53pub struct StorageConfig {
54 props: HashMap<String, String>,
56}
57
58impl StorageConfig {
59 pub fn new() -> Self {
61 Self {
62 props: HashMap::new(),
63 }
64 }
65
66 pub fn from_props(props: HashMap<String, String>) -> Self {
72 Self { props }
73 }
74
75 pub fn props(&self) -> &HashMap<String, String> {
77 &self.props
78 }
79
80 pub fn get(&self, key: &str) -> Option<&String> {
90 self.props.get(key)
91 }
92
93 pub fn with_prop(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
102 self.props.insert(key.into(), value.into());
103 self
104 }
105
106 pub fn with_props(
114 mut self,
115 props: impl IntoIterator<Item = (impl Into<String>, impl Into<String>)>,
116 ) -> Self {
117 self.props
118 .extend(props.into_iter().map(|(k, v)| (k.into(), v.into())));
119 self
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 #[test]
128 fn test_storage_config_new() {
129 let config = StorageConfig::new();
130
131 assert!(config.props().is_empty());
132 }
133
134 #[test]
135 fn test_storage_config_from_props() {
136 let props = HashMap::from([
137 ("region".to_string(), "us-east-1".to_string()),
138 ("bucket".to_string(), "my-bucket".to_string()),
139 ]);
140 let config = StorageConfig::from_props(props.clone());
141
142 assert_eq!(config.props(), &props);
143 }
144
145 #[test]
146 fn test_storage_config_default() {
147 let config = StorageConfig::default();
148
149 assert!(config.props().is_empty());
150 }
151
152 #[test]
153 fn test_storage_config_get() {
154 let config = StorageConfig::new().with_prop("region", "us-east-1");
155
156 assert_eq!(config.get("region"), Some(&"us-east-1".to_string()));
157 assert_eq!(config.get("nonexistent"), None);
158 }
159
160 #[test]
161 fn test_storage_config_with_prop() {
162 let config = StorageConfig::new()
163 .with_prop("region", "us-east-1")
164 .with_prop("bucket", "my-bucket");
165
166 assert_eq!(config.get("region"), Some(&"us-east-1".to_string()));
167 assert_eq!(config.get("bucket"), Some(&"my-bucket".to_string()));
168 }
169
170 #[test]
171 fn test_storage_config_with_props() {
172 let additional_props = vec![("key1", "value1"), ("key2", "value2")];
173 let config = StorageConfig::new().with_props(additional_props);
174
175 assert_eq!(config.get("key1"), Some(&"value1".to_string()));
176 assert_eq!(config.get("key2"), Some(&"value2".to_string()));
177 }
178
179 #[test]
180 fn test_storage_config_clone() {
181 let config = StorageConfig::new().with_prop("region", "us-east-1");
182 let cloned = config.clone();
183
184 assert_eq!(config, cloned);
185 assert_eq!(cloned.get("region"), Some(&"us-east-1".to_string()));
186 }
187
188 #[test]
189 fn test_storage_config_serialization_roundtrip() {
190 let config = StorageConfig::new()
191 .with_prop("region", "us-east-1")
192 .with_prop("bucket", "my-bucket");
193
194 let serialized = serde_json::to_string(&config).unwrap();
195 let deserialized: StorageConfig = serde_json::from_str(&serialized).unwrap();
196
197 assert_eq!(config, deserialized);
198 }
199
200 #[test]
201 fn test_storage_config_clone_independence() {
202 let original = StorageConfig::new().with_prop("region", "us-east-1");
203 let mut cloned = original.clone();
204
205 cloned = cloned.with_prop("region", "eu-west-1");
207 cloned = cloned.with_prop("new_key", "new_value");
208
209 assert_eq!(original.get("region"), Some(&"us-east-1".to_string()));
211 assert_eq!(original.get("new_key"), None);
212
213 assert_eq!(cloned.get("region"), Some(&"eu-west-1".to_string()));
215 assert_eq!(cloned.get("new_key"), Some(&"new_value".to_string()));
216 }
217
218 #[test]
219 fn test_storage_config_from_props_empty() {
220 let config = StorageConfig::from_props(HashMap::new());
221
222 assert!(config.props().is_empty());
223 }
224
225 #[test]
226 fn test_storage_config_serialization_empty() {
227 let config = StorageConfig::new();
228
229 let serialized = serde_json::to_string(&config).unwrap();
230 let deserialized: StorageConfig = serde_json::from_str(&serialized).unwrap();
231
232 assert_eq!(config, deserialized);
233 assert!(deserialized.props().is_empty());
234 }
235}