1pub mod bash_history;
7pub mod bash_script;
8pub mod detect;
9pub mod fish_history;
10pub mod importer;
11pub mod zsh_history;
12
13pub use detect::*;
14pub use importer::*;
15
16#[cfg(test)]
17mod tests {
18 use super::*;
19 use crate::storage::{Paths, SessionStore};
20 use std::path::Path;
21 use tempfile::TempDir;
22
23 #[test]
26 fn test_detect_cast_extension_rejected() {
27 let result = detect_format("recording.cast", "");
28 assert!(result.is_err());
29 let err = result.unwrap_err().to_string();
30 assert!(err.contains("not currently supported"), "Error was: {err}");
31 }
32
33 #[test]
34 fn test_detect_sh_extension() {
35 let result = detect_format("deploy.sh", "echo hello").unwrap();
36 assert_eq!(result, ImportFormat::BashScript);
37 }
38
39 #[test]
40 fn test_detect_bash_extension() {
41 let result = detect_format("setup.bash", "echo hello").unwrap();
42 assert_eq!(result, ImportFormat::BashScript);
43 }
44
45 #[test]
46 fn test_detect_shebang_bash() {
47 let result = detect_format("myscript", "#!/bin/bash\necho hello").unwrap();
48 assert_eq!(result, ImportFormat::BashScript);
49 }
50
51 #[test]
52 fn test_detect_shebang_sh() {
53 let result = detect_format("myscript", "#!/bin/sh\necho hello").unwrap();
54 assert_eq!(result, ImportFormat::BashScript);
55 }
56
57 #[test]
58 fn test_detect_shebang_env_bash() {
59 let result = detect_format("myscript", "#!/usr/bin/env bash\necho hello").unwrap();
60 assert_eq!(result, ImportFormat::BashScript);
61 }
62
63 #[test]
64 fn test_detect_zsh_extended() {
65 let content = ": 1458291931:0;ls -l\n: 1458291945:3;git push";
66 let result = detect_format("history", content).unwrap();
67 assert_eq!(result, ImportFormat::ZshHistory);
68 }
69
70 #[test]
71 fn test_detect_fish_history() {
72 let content = "- cmd: ls -la\n when: 123";
73 let result = detect_format("fish_history", content).unwrap();
74 assert_eq!(result, ImportFormat::FishHistory);
75 }
76
77 #[test]
78 fn test_detect_fallback_bash_history() {
79 let content = "ls -la\ngit status";
80 let result = detect_format("history", content).unwrap();
81 assert_eq!(result, ImportFormat::BashHistory);
82 }
83
84 #[test]
87 fn test_name_from_sh_file() {
88 let name = session_name_from_path(Path::new("deploy.sh"));
89 assert_eq!(name, "deploy-sh");
90 }
91
92 #[test]
93 fn test_name_from_hidden_file() {
94 let name = session_name_from_path(Path::new(".bash_history"));
95 assert_eq!(name, "bash_history");
96 }
97
98 #[test]
99 fn test_name_from_zsh_hidden() {
100 let name = session_name_from_path(Path::new(".zsh_history"));
101 assert_eq!(name, "zsh_history");
102 }
103
104 #[test]
105 fn test_name_with_spaces_and_parens() {
106 let name = session_name_from_path(Path::new("my script (v2).sh"));
107 assert_eq!(name, "my-script-v2-sh");
108 }
109
110 #[test]
111 fn test_name_preserves_underscores() {
112 let name = session_name_from_path(Path::new("my_script.sh"));
113 assert_eq!(name, "my_script-sh");
114 }
115
116 #[test]
117 fn test_name_from_full_path() {
118 let name = session_name_from_path(Path::new("/home/user/.bash_history"));
119 assert_eq!(name, "bash_history");
120 }
121
122 #[test]
123 fn test_name_lowercased() {
124 let name = session_name_from_path(Path::new("DeployScript.SH"));
125 assert_eq!(name, "deployscript-sh");
126 }
127
128 #[test]
131 fn test_format_display() {
132 assert_eq!(ImportFormat::BashScript.to_string(), "bash-script");
133 assert_eq!(ImportFormat::BashHistory.to_string(), "bash-history");
134 assert_eq!(ImportFormat::ZshHistory.to_string(), "zsh-history");
135 assert_eq!(ImportFormat::FishHistory.to_string(), "fish-history");
136 }
137
138 fn create_test_paths(temp_dir: &TempDir) -> Paths {
141 Paths {
142 data_dir: temp_dir.path().join("sessions"),
143 config_dir: temp_dir.path().join("config"),
144 config_file: temp_dir.path().join("config").join("config.toml"),
145 state_dir: temp_dir.path().join("state"),
146 }
147 }
148
149 #[test]
150 fn test_import_bash_script_file() {
151 let temp_dir = TempDir::new().unwrap();
152 let paths = create_test_paths(&temp_dir);
153 let store = SessionStore::new(paths);
154
155 let script_path = temp_dir.path().join("deploy.sh");
156 std::fs::write(&script_path, "#!/bin/bash\n# setup\necho hello\ngit push\n").unwrap();
157
158 let result = import_file(&script_path, None, &store).unwrap();
159
160 assert_eq!(result.session_name, "deploy-sh");
161 assert_eq!(result.command_count, 2);
162 assert_eq!(result.format, ImportFormat::BashScript);
163 assert_eq!(result.preview_commands, vec!["echo hello", "git push"]);
164 }
165
166 #[test]
167 fn test_import_with_name_override() {
168 let temp_dir = TempDir::new().unwrap();
169 let paths = create_test_paths(&temp_dir);
170 let store = SessionStore::new(paths);
171
172 let script_path = temp_dir.path().join("script.sh");
173 std::fs::write(&script_path, "echo hello\n").unwrap();
174
175 let result = import_file(&script_path, Some("custom-name"), &store).unwrap();
176 assert_eq!(result.session_name, "custom-name");
177 }
178
179 #[test]
180 fn test_import_empty_file_errors() {
181 let temp_dir = TempDir::new().unwrap();
182 let paths = create_test_paths(&temp_dir);
183 let store = SessionStore::new(paths);
184
185 let script_path = temp_dir.path().join("empty.sh");
186 std::fs::write(&script_path, "#!/bin/bash\n# only comments\n").unwrap();
187
188 let result = import_file(&script_path, None, &store);
189 assert!(result.is_err());
190 let err = result.unwrap_err().to_string();
191 assert!(err.contains("No commands found"), "Error was: {err}");
192 }
193
194 #[test]
195 fn test_import_preview_capped_at_5() {
196 let temp_dir = TempDir::new().unwrap();
197 let paths = create_test_paths(&temp_dir);
198 let store = SessionStore::new(paths);
199
200 let script_path = temp_dir.path().join("many.sh");
201 std::fs::write(
202 &script_path,
203 "cmd1\ncmd2\ncmd3\ncmd4\ncmd5\ncmd6\ncmd7\ncmd8\n",
204 )
205 .unwrap();
206
207 let result = import_file(&script_path, None, &store).unwrap();
208 assert_eq!(result.command_count, 8);
209 assert_eq!(result.preview_commands.len(), 5);
210 }
211
212 #[test]
213 fn test_import_cast_file_rejected() {
214 let temp_dir = TempDir::new().unwrap();
215 let paths = create_test_paths(&temp_dir);
216 let store = SessionStore::new(paths);
217
218 let cast_path = temp_dir.path().join("recording.cast");
219 std::fs::write(&cast_path, "some asciinema content").unwrap();
220
221 let result = import_file(&cast_path, None, &store);
222 assert!(result.is_err());
223 let err = result.unwrap_err().to_string();
224 assert!(err.contains("not currently supported"), "Error was: {err}");
225 }
226
227 #[test]
228 fn test_import_session_persisted() {
229 let temp_dir = TempDir::new().unwrap();
230 let paths = create_test_paths(&temp_dir);
231 let store = SessionStore::new(paths);
232
233 let script_path = temp_dir.path().join("test.sh");
234 std::fs::write(&script_path, "echo hello\nls\n").unwrap();
235
236 let result = import_file(&script_path, None, &store).unwrap();
237
238 let sessions = store.list().unwrap();
240 assert_eq!(sessions.len(), 1);
241
242 let loaded = store.load(&sessions[0]).unwrap();
244 assert_eq!(loaded.header.name, result.session_name);
245 assert_eq!(loaded.commands.len(), 2);
246 assert!(loaded.footer.is_some());
247 }
248}