command_stream/commands/
basename.rs1use crate::commands::CommandContext;
4use crate::utils::{CommandResult, VirtualUtils};
5use std::path::Path;
6
7pub async fn basename(ctx: CommandContext) -> CommandResult {
11 if ctx.args.is_empty() {
12 return VirtualUtils::missing_operand_error("basename");
13 }
14
15 let path = &ctx.args[0];
16 let suffix = ctx.args.get(1);
17
18 let base = Path::new(path)
19 .file_name()
20 .map(|n| n.to_string_lossy().to_string())
21 .unwrap_or_default();
22
23 let result = if let Some(suf) = suffix {
24 if base.ends_with(suf.as_str()) {
25 base[..base.len() - suf.len()].to_string()
26 } else {
27 base
28 }
29 } else {
30 base
31 };
32
33 CommandResult::success(format!("{}\n", result))
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[tokio::test]
41 async fn test_basename_simple() {
42 let ctx = CommandContext::new(vec!["/path/to/file.txt".to_string()]);
43 let result = basename(ctx).await;
44
45 assert!(result.is_success());
46 assert_eq!(result.stdout, "file.txt\n");
47 }
48
49 #[tokio::test]
50 async fn test_basename_with_suffix() {
51 let ctx = CommandContext::new(vec!["/path/to/file.txt".to_string(), ".txt".to_string()]);
52 let result = basename(ctx).await;
53
54 assert!(result.is_success());
55 assert_eq!(result.stdout, "file\n");
56 }
57
58 #[tokio::test]
59 async fn test_basename_no_path() {
60 let ctx = CommandContext::new(vec!["file.txt".to_string()]);
61 let result = basename(ctx).await;
62
63 assert!(result.is_success());
64 assert_eq!(result.stdout, "file.txt\n");
65 }
66}