airsprotocols_mcpserver_filesystem/filesystem/
operations.rs

1//! Core filesystem operations and tracking
2
3// Layer 1: Standard library imports
4use std::path::PathBuf;
5
6// Layer 2: Third-party crate imports
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9
10// Layer 3: Internal module imports
11use crate::mcp::OperationType;
12
13/// Represents a filesystem operation with metadata
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct FileOperation {
16    /// Type of operation being performed
17    pub operation_type: OperationType,
18    /// Path to the file or directory
19    pub path: PathBuf,
20    /// Timestamp when operation was created
21    pub timestamp: DateTime<Utc>,
22    /// Unique operation identifier
23    pub operation_id: String,
24}
25
26impl FileOperation {
27    /// Create a new file operation
28    pub fn new(operation_type: OperationType, path: PathBuf) -> Self {
29        Self {
30            operation_type,
31            path,
32            timestamp: Utc::now(), // ยง 3.2 compliance
33            operation_id: uuid::Uuid::new_v4().to_string(),
34        }
35    }
36
37    /// Get the operation as a human-readable string
38    pub fn description(&self) -> String {
39        format!(
40            "{:?} operation on '{}'",
41            self.operation_type,
42            self.path.display()
43        )
44    }
45}
46
47#[cfg(test)]
48#[allow(clippy::unwrap_used)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_file_operation_creation() {
54        let path = PathBuf::from("/test/path.txt");
55        let op = FileOperation::new(OperationType::Read, path.clone());
56        
57        assert_eq!(op.operation_type, OperationType::Read);
58        assert_eq!(op.path, path);
59        assert!(!op.operation_id.is_empty());
60        // Timestamp should be recent (within last second)
61        let now = Utc::now();
62        let diff = now.signed_duration_since(op.timestamp);
63        assert!(diff.num_seconds() < 1);
64    }
65
66    #[test]
67    fn test_operation_description() {
68        let path = PathBuf::from("/test/file.txt");
69        let op = FileOperation::new(OperationType::Write, path);
70        
71        let desc = op.description();
72        assert!(desc.contains("Write"));
73        assert!(desc.contains("/test/file.txt"));
74    }
75
76    #[test]
77    fn test_operation_serialization() {
78        let path = PathBuf::from("/test/serialize.txt");
79        let op = FileOperation::new(OperationType::List, path);
80        
81        let serialized = serde_json::to_string(&op).unwrap();
82        let deserialized: FileOperation = serde_json::from_str(&serialized).unwrap();
83        
84        assert_eq!(op.operation_type, deserialized.operation_type);
85        assert_eq!(op.path, deserialized.path);
86        assert_eq!(op.operation_id, deserialized.operation_id);
87    }
88}