command_stream/commands/
dirname.rs1use crate::commands::CommandContext;
4use crate::utils::{CommandResult, VirtualUtils};
5use std::path::Path;
6
7pub async fn dirname(ctx: CommandContext) -> CommandResult {
11 if ctx.args.is_empty() {
12 return VirtualUtils::missing_operand_error("dirname");
13 }
14
15 let path = &ctx.args[0];
16 let parent = Path::new(path)
17 .parent()
18 .map(|p| p.to_string_lossy().to_string())
19 .unwrap_or_else(|| ".".to_string());
20
21 let result = if parent.is_empty() { "." } else { &parent };
23
24 CommandResult::success(format!("{}\n", result))
25}
26
27#[cfg(test)]
28mod tests {
29 use super::*;
30
31 #[tokio::test]
32 async fn test_dirname_simple() {
33 let ctx = CommandContext::new(vec!["/path/to/file.txt".to_string()]);
34 let result = dirname(ctx).await;
35
36 assert!(result.is_success());
37 assert_eq!(result.stdout, "/path/to\n");
38 }
39
40 #[tokio::test]
41 async fn test_dirname_just_file() {
42 let ctx = CommandContext::new(vec!["file.txt".to_string()]);
43 let result = dirname(ctx).await;
44
45 assert!(result.is_success());
46 assert_eq!(result.stdout, ".\n");
47 }
48
49 #[tokio::test]
50 async fn test_dirname_root() {
51 let ctx = CommandContext::new(vec!["/file.txt".to_string()]);
52 let result = dirname(ctx).await;
53
54 assert!(result.is_success());
55 assert_eq!(result.stdout, "/\n");
56 }
57}