1use crate::agent::StepError;
2use std::fs::OpenOptions;
3use std::io::Write;
4
5pub fn read_file(path: &str) -> Result<String, StepError> {
7 Ok(std::fs::read_to_string(path)?)
8}
9pub fn write_file(path: &str, content: &str) -> Result<(), StepError> {
11 if let Some(parent) = std::path::Path::new(path).parent() {
12 std::fs::create_dir_all(parent)?;
13 }
14 Ok(std::fs::write(path, content)?)
15}
16
17pub fn list_dir(path: &str) -> Result<Vec<String>, StepError> {
19 let mut entries = Vec::new();
20 for entry in std::fs::read_dir(path)? {
21 let entry = entry?;
22 entries.push(entry.path().display().to_string());
23 }
24 Ok(entries)
25}
26pub fn find_files(path: &str, pattern: &str) -> Result<Vec<String>, StepError> {
28 let mut results = Vec::new();
29 find_files_recursive(path, pattern, &mut results)?;
30 Ok(results)
31}
32
33fn find_files_recursive(
34 dir: &str,
35 pattern: &str,
36 results: &mut Vec<String>,
37) -> Result<(), StepError> {
38 for entry in std::fs::read_dir(dir)? {
39 let entry = entry?;
40 let path = entry.path();
41
42 if path.is_dir() {
43 find_files_recursive(&path.display().to_string(), pattern, results)?;
44 } else if let Some(name) = path.file_name().and_then(|n| n.to_str())
45 && name.ends_with(pattern.trim_start_matches('*'))
46 {
47 results.push(path.display().to_string());
48 }
49 }
50 Ok(())
51}
52
53pub fn append_file(file_path: &str, content: &str) -> Result<(), StepError> {
55 let mut file = OpenOptions::new()
56 .append(true)
57 .create(true)
58 .open(file_path)?;
59
60 file.write_all(content.as_bytes())?;
61 Ok(())
62}
63
64pub fn file_exists(file_path: &str) -> bool {
66 std::path::Path::new(file_path).exists()
67}
68
69pub fn delete_file(file_path: &str) -> Result<(), StepError> {
71 std::fs::remove_file(file_path)?;
72 Ok(())
73}
74
75pub fn create_dir(name: &str) -> Result<(), StepError> {
77 std::fs::create_dir_all(name)?;
78 Ok(())
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_append_to_existing_file() {
87 let path = "/tmp/agent_line_test_append.txt";
88 let _ = std::fs::remove_file(path);
89 write_file(path, "hello").unwrap();
90 append_file(path, " world").unwrap();
91 assert_eq!(read_file(path).unwrap(), "hello world");
92 std::fs::remove_file(path).unwrap();
93 }
94
95 #[test]
96 fn test_append_creates_file_if_missing() {
97 let path = "/tmp/agent_line_test_append_new.txt";
98 let _ = std::fs::remove_file(path);
99 append_file(path, "new content").unwrap();
100 assert_eq!(read_file(path).unwrap(), "new content");
101 std::fs::remove_file(path).unwrap();
102 }
103
104 #[test]
105 fn test_file_exists_true() {
106 let path = "/tmp/agent_line_test_exists.txt";
107 write_file(path, "data").unwrap();
108 assert!(file_exists(path));
109 std::fs::remove_file(path).unwrap();
110 }
111
112 #[test]
113 fn test_file_exists_false() {
114 assert!(!file_exists("/tmp/agent_line_nonexistent_xyz.txt"));
115 }
116
117 #[test]
118 fn test_delete_file_removes_it() {
119 let path = "/tmp/agent_line_test_delete.txt";
120 write_file(path, "data").unwrap();
121 delete_file(path).unwrap();
122 assert!(!file_exists(path));
123 }
124
125 #[test]
126 fn test_delete_file_not_found_is_error() {
127 let result = delete_file("/tmp/agent_line_no_such_file_xyz.txt");
128 assert!(result.is_err());
129 }
130
131 #[test]
132 fn test_create_dir_simple() {
133 let path = "/tmp/agent_line_test_dir";
134 let _ = std::fs::remove_dir_all(path);
135 create_dir(path).unwrap();
136 assert!(std::path::Path::new(path).is_dir());
137 std::fs::remove_dir_all(path).unwrap();
138 }
139
140 #[test]
141 fn test_create_dir_nested() {
142 let path = "/tmp/agent_line_test_dir_nested/a/b/c";
143 let _ = std::fs::remove_dir_all("/tmp/agent_line_test_dir_nested");
144 create_dir(path).unwrap();
145 assert!(std::path::Path::new(path).is_dir());
146 std::fs::remove_dir_all("/tmp/agent_line_test_dir_nested").unwrap();
147 }
148}