clnrm_core/
utils.rs

1//! Utility functions and helpers for the cleanroom framework
2//!
3//! Contains common utilities used throughout the framework.
4
5use crate::error::Result;
6
7/// Validate a file path exists and is readable
8pub fn validate_file_path(path: &str) -> Result<()> {
9    use std::path::Path;
10    
11    let path_obj = Path::new(path);
12    
13    // Check if path exists
14    if !path_obj.exists() {
15        return Err(crate::error::CleanroomError::validation_error(&format!(
16            "Path does not exist: {}", path
17        )));
18    }
19    
20    // Check if path is readable (file) or accessible (directory)
21    if path_obj.is_file() {
22        // For files, check if we can read metadata
23        std::fs::metadata(path_obj)?;
24    } else if path_obj.is_dir() {
25        // For directories, check if we can read the directory
26        std::fs::read_dir(path_obj)?;
27    } else {
28        return Err(crate::error::CleanroomError::validation_error(&format!(
29            "Path is neither a file nor directory: {}", path
30        )));
31    }
32    
33    Ok(())
34}
35
36/// Parse a TOML configuration file
37pub fn parse_toml_config(content: &str) -> Result<serde_json::Value> {
38    // Parse TOML content
39    let toml_value: toml::Value = toml::from_str(content)
40        .map_err(|e| crate::error::CleanroomError::validation_error(&format!(
41            "Invalid TOML syntax: {}", e
42        )))?;
43    
44    // Convert TOML to JSON for consistent handling
45    let json_value = serde_json::to_value(toml_value)
46        .map_err(|e| crate::error::CleanroomError::internal_error(&format!(
47            "Failed to convert TOML to JSON: {}", e
48        )))?;
49    
50    Ok(json_value)
51}
52
53/// Generate a unique session ID
54pub fn generate_session_id() -> String {
55    format!("session_{}", uuid::Uuid::new_v4())
56}
57
58/// Format duration for display
59pub fn format_duration(duration: std::time::Duration) -> String {
60    if duration.as_secs() > 0 {
61        format!("{:.2}s", duration.as_secs_f64())
62    } else if duration.as_millis() > 0 {
63        format!("{}ms", duration.as_millis())
64    } else {
65        format!("{}μs", duration.as_micros())
66    }
67}
68
69/// Validate regex pattern
70pub fn validate_regex(pattern: &str) -> Result<()> {
71    use regex::Regex;
72    
73    // Try to compile the regex pattern
74    Regex::new(pattern)
75        .map_err(|e| crate::error::CleanroomError::validation_error(&format!(
76            "Invalid regex pattern '{}': {}", pattern, e
77        )))?;
78    
79    Ok(())
80}
81
82/// Execute regex pattern matching
83pub fn execute_regex_match(text: &str, pattern: &str) -> Result<bool> {
84    use regex::Regex;
85    
86    // Compile and execute regex
87    let regex = Regex::new(pattern)
88        .map_err(|e| crate::error::CleanroomError::validation_error(&format!(
89            "Invalid regex pattern '{}': {}", pattern, e
90        )))?;
91    
92    Ok(regex.is_match(text))
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_validate_file_path() {
101        // Test with existing file (current directory)
102        let result = validate_file_path(".");
103        assert!(result.is_ok());
104        
105        // Test with nonexistent file
106        let result = validate_file_path("nonexistent.txt");
107        assert!(result.is_err());
108    }
109
110    #[test]
111    fn test_parse_toml_config() {
112        // Test with valid TOML
113        let result = parse_toml_config("[test]\nname = \"example\"");
114        assert!(result.is_ok());
115        
116        // Test with invalid TOML
117        let result = parse_toml_config("invalid toml");
118        assert!(result.is_err());
119    }
120
121    #[test]
122    fn test_generate_session_id() {
123        let id = generate_session_id();
124        assert!(id.starts_with("session_"));
125        assert!(id.len() > 8); // Should contain UUID
126    }
127
128    #[test]
129    fn test_format_duration() {
130        let duration = std::time::Duration::from_millis(1500);
131        let formatted = format_duration(duration);
132        assert!(formatted.contains("1.50s"));
133
134        let duration = std::time::Duration::from_millis(500);
135        let formatted = format_duration(duration);
136        assert!(formatted.contains("500ms"));
137    }
138}