From 6714afe2d7cf4ab8e9919f844542ed355846edbf Mon Sep 17 00:00:00 2001 From: Daniel Edrisian Date: Mon, 25 Aug 2025 18:42:57 -0700 Subject: [PATCH] Tests --- codex-rs/tui/src/bottom_pane/chat_composer.rs | 30 ++++++++++++ codex-rs/tui/src/bottom_pane/command_popup.rs | 49 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index c02e4cdf18..6c76f6a1ea 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -1988,4 +1988,34 @@ mod tests { let imgs = composer.take_recent_submission_images(); assert_eq!(imgs, vec![tmp_path.clone()]); } + + #[test] + fn selecting_custom_prompt_submits_file_contents() { + let tmp = tempdir().expect("create TempDir"); + let home = tmp.path(); + let prompts_dir = home.join(".codex").join("prompts"); + std::fs::create_dir_all(&prompts_dir).expect("mkdir -p ~/.codex/prompts"); + let prompt_path = prompts_dir.join("my-prompt"); + let prompt_text = "Hello from saved prompt"; + std::fs::write(&prompt_path, prompt_text).unwrap(); + + unsafe { std::env::set_var("HOME", home) }; + + let (tx, _rx) = unbounded_channel::(); + let sender = AppEventSender::new(tx); + let mut composer = + ChatComposer::new(true, sender, false, "Ask Codex to do anything".to_string()); + + // Type the prompt name to focus it in the slash popup and press Enter. + for ch in ['/', 'm', 'y', '-', 'p', 'r', 'o', 'm', 'p', 't'] { + let _ = composer.handle_key_event(KeyEvent::new(KeyCode::Char(ch), KeyModifiers::NONE)); + } + let (result, _needs_redraw) = + composer.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); + + match result { + InputResult::Submitted(s) => assert_eq!(s, prompt_text), + _ => panic!("expected Submitted with prompt contents"), + } + } } diff --git a/codex-rs/tui/src/bottom_pane/command_popup.rs b/codex-rs/tui/src/bottom_pane/command_popup.rs index 30c8126850..33ad2e7888 100644 --- a/codex-rs/tui/src/bottom_pane/command_popup.rs +++ b/codex-rs/tui/src/bottom_pane/command_popup.rs @@ -229,6 +229,7 @@ impl WidgetRef for CommandPopup { #[cfg(test)] mod tests { use super::*; + use tempfile::tempdir; #[test] fn filter_includes_init_when_typing_prefix() { @@ -264,4 +265,52 @@ mod tests { None => panic!("expected a selected command for exact match"), } } + + #[test] + fn prompt_discovery_lists_custom_prompts() { + let tmp = tempdir().expect("create TempDir"); + let home = tmp.path(); + let prompts_dir = home.join(".codex").join("prompts"); + std::fs::create_dir_all(&prompts_dir).expect("mkdir -p ~/.codex/prompts"); + std::fs::write(prompts_dir.join("foo"), b"hello from foo").unwrap(); + std::fs::write(prompts_dir.join("bar"), b"hello from bar").unwrap(); + + // Point HOME to the temp dir so discovery uses our fixtures. + unsafe { std::env::set_var("HOME", home) }; + + let popup = CommandPopup::new(); + let items = popup.filtered_items(); + let mut prompt_names: Vec = items + .into_iter() + .filter_map(|it| match it { + CommandItem::Prompt(i) => popup.prompt_name(i).map(|s| s.to_string()), + _ => None, + }) + .collect(); + prompt_names.sort(); + assert_eq!(prompt_names, vec!["bar".to_string(), "foo".to_string()]); + } + + #[test] + fn prompt_name_collision_with_builtin_is_ignored() { + let tmp = tempdir().expect("create TempDir"); + let home = tmp.path(); + let prompts_dir = home.join(".codex").join("prompts"); + std::fs::create_dir_all(&prompts_dir).expect("mkdir -p ~/.codex/prompts"); + // Create a prompt with the same name as a builtin command (e.g. "init"). + std::fs::write(prompts_dir.join("init"), b"should be ignored").unwrap(); + + unsafe { std::env::set_var("HOME", home) }; + + let popup = CommandPopup::new(); + let items = popup.filtered_items(); + let has_collision_prompt = items.into_iter().any(|it| match it { + CommandItem::Prompt(i) => popup.prompt_name(i) == Some("init"), + _ => false, + }); + assert!( + !has_collision_prompt, + "prompt with builtin name should be ignored" + ); + } }