1use lnmp_core::FieldId;
28use std::collections::HashMap;
29
30#[derive(Debug, Clone)]
36pub struct EquivalenceMapper {
37 mappings: HashMap<FieldId, HashMap<String, String>>,
39}
40
41impl EquivalenceMapper {
42 pub fn new() -> Self {
44 Self {
45 mappings: HashMap::new(),
46 }
47 }
48
49 pub fn with_defaults() -> Self {
54 Self::new()
55 }
56
57 pub fn add_mapping(&mut self, fid: FieldId, from: String, to: String) {
78 self.mappings.entry(fid).or_default().insert(from, to);
79 }
80
81 pub fn add_mappings<I>(&mut self, fid: FieldId, mappings: I)
88 where
89 I: IntoIterator<Item = (String, String)>,
90 {
91 let field_mappings = self.mappings.entry(fid).or_default();
92 for (from, to) in mappings {
93 field_mappings.insert(from, to);
94 }
95 }
96
97 pub fn apply_default_bool_mappings(&mut self, fid: FieldId) {
117 let bool_mappings = vec![
118 ("yes".to_string(), "1".to_string()),
119 ("Yes".to_string(), "1".to_string()),
120 ("YES".to_string(), "1".to_string()),
121 ("true".to_string(), "1".to_string()),
122 ("True".to_string(), "1".to_string()),
123 ("TRUE".to_string(), "1".to_string()),
124 ("no".to_string(), "0".to_string()),
125 ("No".to_string(), "0".to_string()),
126 ("NO".to_string(), "0".to_string()),
127 ("false".to_string(), "0".to_string()),
128 ("False".to_string(), "0".to_string()),
129 ("FALSE".to_string(), "0".to_string()),
130 ];
131 self.add_mappings(fid, bool_mappings);
132 }
133
134 pub fn map(&self, fid: FieldId, value: &str) -> Option<String> {
157 self.mappings
158 .get(&fid)
159 .and_then(|field_mappings| field_mappings.get(value))
160 .cloned()
161 }
162
163 pub fn has_mapping(&self, fid: FieldId, value: &str) -> bool {
170 self.mappings
171 .get(&fid)
172 .map(|field_mappings| field_mappings.contains_key(value))
173 .unwrap_or(false)
174 }
175
176 pub fn field_count(&self) -> usize {
178 self.mappings.len()
179 }
180
181 pub fn mapping_count(&self, fid: FieldId) -> usize {
187 self.mappings
188 .get(&fid)
189 .map(|field_mappings| field_mappings.len())
190 .unwrap_or(0)
191 }
192
193 pub fn clear_field(&mut self, fid: FieldId) {
199 self.mappings.remove(&fid);
200 }
201
202 pub fn clear(&mut self) {
204 self.mappings.clear();
205 }
206}
207
208impl Default for EquivalenceMapper {
209 fn default() -> Self {
210 Self::new()
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_new_mapper_is_empty() {
220 let mapper = EquivalenceMapper::new();
221 assert_eq!(mapper.field_count(), 0);
222 }
223
224 #[test]
225 fn test_add_single_mapping() {
226 let mut mapper = EquivalenceMapper::new();
227 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
228
229 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
230 assert_eq!(mapper.map(12, "user"), None);
231 assert_eq!(mapper.field_count(), 1);
232 assert_eq!(mapper.mapping_count(12), 1);
233 }
234
235 #[test]
236 fn test_add_multiple_mappings_same_field() {
237 let mut mapper = EquivalenceMapper::new();
238 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
239 mapper.add_mapping(12, "dev".to_string(), "developer".to_string());
240 mapper.add_mapping(12, "qa".to_string(), "quality_assurance".to_string());
241
242 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
243 assert_eq!(mapper.map(12, "dev"), Some("developer".to_string()));
244 assert_eq!(mapper.map(12, "qa"), Some("quality_assurance".to_string()));
245 assert_eq!(mapper.field_count(), 1);
246 assert_eq!(mapper.mapping_count(12), 3);
247 }
248
249 #[test]
250 fn test_add_mappings_different_fields() {
251 let mut mapper = EquivalenceMapper::new();
252 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
253 mapper.add_mapping(7, "yes".to_string(), "1".to_string());
254
255 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
256 assert_eq!(mapper.map(7, "yes"), Some("1".to_string()));
257 assert_eq!(mapper.map(12, "yes"), None); assert_eq!(mapper.map(7, "admin"), None); assert_eq!(mapper.field_count(), 2);
260 }
261
262 #[test]
263 fn test_add_mappings_bulk() {
264 let mut mapper = EquivalenceMapper::new();
265 let mappings = vec![
266 ("admin".to_string(), "administrator".to_string()),
267 ("dev".to_string(), "developer".to_string()),
268 ("qa".to_string(), "quality_assurance".to_string()),
269 ];
270 mapper.add_mappings(12, mappings);
271
272 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
273 assert_eq!(mapper.map(12, "dev"), Some("developer".to_string()));
274 assert_eq!(mapper.map(12, "qa"), Some("quality_assurance".to_string()));
275 assert_eq!(mapper.mapping_count(12), 3);
276 }
277
278 #[test]
279 fn test_apply_default_bool_mappings() {
280 let mut mapper = EquivalenceMapper::new();
281 mapper.apply_default_bool_mappings(7);
282
283 assert_eq!(mapper.map(7, "yes"), Some("1".to_string()));
285 assert_eq!(mapper.map(7, "Yes"), Some("1".to_string()));
286 assert_eq!(mapper.map(7, "YES"), Some("1".to_string()));
287 assert_eq!(mapper.map(7, "true"), Some("1".to_string()));
288 assert_eq!(mapper.map(7, "True"), Some("1".to_string()));
289 assert_eq!(mapper.map(7, "TRUE"), Some("1".to_string()));
290
291 assert_eq!(mapper.map(7, "no"), Some("0".to_string()));
293 assert_eq!(mapper.map(7, "No"), Some("0".to_string()));
294 assert_eq!(mapper.map(7, "NO"), Some("0".to_string()));
295 assert_eq!(mapper.map(7, "false"), Some("0".to_string()));
296 assert_eq!(mapper.map(7, "False"), Some("0".to_string()));
297 assert_eq!(mapper.map(7, "FALSE"), Some("0".to_string()));
298
299 assert_eq!(mapper.map(7, "maybe"), None);
301 assert_eq!(mapper.map(7, "1"), None);
302 assert_eq!(mapper.map(7, "0"), None);
303 }
304
305 #[test]
306 fn test_has_mapping() {
307 let mut mapper = EquivalenceMapper::new();
308 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
309
310 assert!(mapper.has_mapping(12, "admin"));
311 assert!(!mapper.has_mapping(12, "user"));
312 assert!(!mapper.has_mapping(7, "admin"));
313 }
314
315 #[test]
316 fn test_mapping_count() {
317 let mut mapper = EquivalenceMapper::new();
318 assert_eq!(mapper.mapping_count(12), 0);
319
320 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
321 assert_eq!(mapper.mapping_count(12), 1);
322
323 mapper.add_mapping(12, "dev".to_string(), "developer".to_string());
324 assert_eq!(mapper.mapping_count(12), 2);
325
326 mapper.add_mapping(7, "yes".to_string(), "1".to_string());
327 assert_eq!(mapper.mapping_count(12), 2);
328 assert_eq!(mapper.mapping_count(7), 1);
329 }
330
331 #[test]
332 fn test_field_count() {
333 let mut mapper = EquivalenceMapper::new();
334 assert_eq!(mapper.field_count(), 0);
335
336 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
337 assert_eq!(mapper.field_count(), 1);
338
339 mapper.add_mapping(12, "dev".to_string(), "developer".to_string());
340 assert_eq!(mapper.field_count(), 1); mapper.add_mapping(7, "yes".to_string(), "1".to_string());
343 assert_eq!(mapper.field_count(), 2); }
345
346 #[test]
347 fn test_clear_field() {
348 let mut mapper = EquivalenceMapper::new();
349 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
350 mapper.add_mapping(12, "dev".to_string(), "developer".to_string());
351 mapper.add_mapping(7, "yes".to_string(), "1".to_string());
352
353 assert_eq!(mapper.field_count(), 2);
354 assert_eq!(mapper.mapping_count(12), 2);
355
356 mapper.clear_field(12);
357 assert_eq!(mapper.field_count(), 1);
358 assert_eq!(mapper.mapping_count(12), 0);
359 assert_eq!(mapper.mapping_count(7), 1);
360 assert_eq!(mapper.map(12, "admin"), None);
361 assert_eq!(mapper.map(7, "yes"), Some("1".to_string()));
362 }
363
364 #[test]
365 fn test_clear_all() {
366 let mut mapper = EquivalenceMapper::new();
367 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
368 mapper.add_mapping(7, "yes".to_string(), "1".to_string());
369
370 assert_eq!(mapper.field_count(), 2);
371
372 mapper.clear();
373 assert_eq!(mapper.field_count(), 0);
374 assert_eq!(mapper.map(12, "admin"), None);
375 assert_eq!(mapper.map(7, "yes"), None);
376 }
377
378 #[test]
379 fn test_overwrite_mapping() {
380 let mut mapper = EquivalenceMapper::new();
381 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
382 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
383
384 mapper.add_mapping(12, "admin".to_string(), "superuser".to_string());
386 assert_eq!(mapper.map(12, "admin"), Some("superuser".to_string()));
387 assert_eq!(mapper.mapping_count(12), 1);
388 }
389
390 #[test]
391 fn test_case_sensitive_mapping() {
392 let mut mapper = EquivalenceMapper::new();
393 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
394 mapper.add_mapping(12, "Admin".to_string(), "Administrator".to_string());
395
396 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
397 assert_eq!(mapper.map(12, "Admin"), Some("Administrator".to_string()));
398 assert_eq!(mapper.map(12, "ADMIN"), None);
399 }
400
401 #[test]
402 fn test_empty_string_mapping() {
403 let mut mapper = EquivalenceMapper::new();
404 mapper.add_mapping(12, "".to_string(), "empty".to_string());
405
406 assert_eq!(mapper.map(12, ""), Some("empty".to_string()));
407 }
408
409 #[test]
410 fn test_with_defaults() {
411 let mapper = EquivalenceMapper::with_defaults();
412 assert_eq!(mapper.field_count(), 0);
413 }
414
415 #[test]
416 fn test_default_trait() {
417 let mapper = EquivalenceMapper::default();
418 assert_eq!(mapper.field_count(), 0);
419 }
420
421 #[test]
422 fn test_clone() {
423 let mut mapper = EquivalenceMapper::new();
424 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
425
426 let cloned = mapper.clone();
427 assert_eq!(cloned.map(12, "admin"), Some("administrator".to_string()));
428 assert_eq!(cloned.field_count(), 1);
429 }
430
431 #[test]
432 fn test_multiple_fields_with_same_mapping_value() {
433 let mut mapper = EquivalenceMapper::new();
434 mapper.add_mapping(12, "admin".to_string(), "administrator".to_string());
435 mapper.add_mapping(15, "admin".to_string(), "admin_user".to_string());
436
437 assert_eq!(mapper.map(12, "admin"), Some("administrator".to_string()));
439 assert_eq!(mapper.map(15, "admin"), Some("admin_user".to_string()));
440 }
441
442 #[test]
443 fn test_unicode_mapping() {
444 let mut mapper = EquivalenceMapper::new();
445 mapper.add_mapping(12, "café".to_string(), "coffee_shop".to_string());
446 mapper.add_mapping(12, "日本".to_string(), "japan".to_string());
447
448 assert_eq!(mapper.map(12, "café"), Some("coffee_shop".to_string()));
449 assert_eq!(mapper.map(12, "日本"), Some("japan".to_string()));
450 }
451}