diff --git a/src/tag_engine.rs b/src/tag_engine.rs index 8b03a4d..b3aee70 100644 --- a/src/tag_engine.rs +++ b/src/tag_engine.rs @@ -92,6 +92,42 @@ pub fn parse_tags(filename: &str) -> Result<(String, Vec, String), Parse Ok((base_name, tags, extension)) } +pub fn create_tag_combinations(tags: &[String], depth: usize) -> Vec> { + let mut result = Vec::new(); + + // Handle empty tags or depth 0 + if tags.is_empty() || depth == 0 { + return result; + } + + // Add individual tags first + for tag in tags { + result.push(vec![tag.clone()]); + } + + // Generate combinations up to specified depth + for len in 2..=depth.min(tags.len()) { + let mut temp = Vec::new(); + + // Start with existing combinations of length-1 + for combo in result.iter().filter(|c| c.len() == len - 1) { + // Try to add each remaining tag that comes after the last tag in combo + if let Some(last) = combo.last() { + for tag in tags { + if tag > last && !combo.contains(tag) { + let mut new_combo = combo.clone(); + new_combo.push(tag.clone()); + temp.push(new_combo); + } + } + } + } + result.extend(temp); + } + + result +} + pub fn filter_tags(current: Vec, remove: &[String]) -> Vec { current.into_iter() .filter(|tag| !remove.contains(tag)) @@ -287,4 +323,44 @@ mod tests { let result = filter_tags(current, &remove); assert!(result.is_empty()); } + + #[test] + fn test_create_tag_combinations_empty() { + let tags: Vec = vec![]; + let result = create_tag_combinations(&tags, 2); + assert!(result.is_empty()); + } + + #[test] + fn test_create_tag_combinations_depth_limit() { + let tags = vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()]; + let result = create_tag_combinations(&tags, 2); + + // Should contain individual tags and pairs, but no triples + assert!(result.iter().all(|combo| combo.len() <= 2)); + assert_eq!(result.len(), 6); // 3 individual + 3 pairs + } + + #[test] + fn test_create_tag_combinations_order() { + let tags = vec!["tag2".to_string(), "tag1".to_string(), "tag3".to_string()]; + let result = create_tag_combinations(&tags, 2); + + // Check that all combinations maintain alphabetical order + for combo in result { + if combo.len() > 1 { + assert!(combo.windows(2).all(|w| w[0] < w[1])); + } + } + } + + #[test] + fn test_create_tag_combinations_uniqueness() { + let tags = vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()]; + let result = create_tag_combinations(&tags, 3); + + // Convert to set to check for duplicates + let result_set: std::collections::HashSet<_> = result.into_iter().collect(); + assert_eq!(result_set.len(), 7); // 3 individual + 3 pairs + 1 triple + } }