From da6128cb9f550c4ca9ffe3bb700b2fab876afb71 Mon Sep 17 00:00:00 2001 From: kuddev Date: Sun, 20 Sep 2026 15:57:26 +0800 Subject: [PATCH] test(terminal): verify history separately from runtime command identity --- nebula_app/src/gpui_shell/terminal/suggest.rs | 8 +++++ .../terminal/view/native_cmd_tests.rs | 35 ++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/nebula_app/src/gpui_shell/terminal/suggest.rs b/nebula_app/src/gpui_shell/terminal/suggest.rs index 2835e37..ff3831b 100644 --- a/nebula_app/src/gpui_shell/terminal/suggest.rs +++ b/nebula_app/src/gpui_shell/terminal/suggest.rs @@ -38,6 +38,14 @@ fn shared() -> MutexGuard<'static, Shared> { .unwrap_or_else(std::sync::PoisonError::into_inner) } +#[cfg(test)] +pub(super) fn history_hint_for_test( + scope: &crate::nebula_history::HistoryScope, + prefix: &str, +) -> Option { + shared().history.hint(scope, prefix).map(str::to_owned) +} + /// 重算一个 pane 的 ghost/弹窗建议。`line_override` 是 grid 读出的屏幕真值 /// (Windows 唯一行来源,见旧壳 `nebula_input_from_raw_grid` 的契约)。 pub fn update( diff --git a/nebula_app/src/gpui_shell/terminal/view/native_cmd_tests.rs b/nebula_app/src/gpui_shell/terminal/view/native_cmd_tests.rs index 183172a..b466829 100644 --- a/nebula_app/src/gpui_shell/terminal/view/native_cmd_tests.rs +++ b/nebula_app/src/gpui_shell/terminal/view/native_cmd_tests.rs @@ -83,8 +83,17 @@ fn custom_native_prompts_capture_recalled_input_and_keep_submission_epochs( fn custom_native_prompts_handle_empty_submit_paste_and_runtime_without_fake_history( cx: &mut gpui::TestAppContext, ) { - for prompt in ["", "[C:\\work] ", "[C:\\work]\r\n>", &"x".repeat(80), &"x".repeat(160)] { + let nonce = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos(); + for (index, prompt) in ["", "[C:\\work] ", "[C:\\work]\r\n>", &"x".repeat(80), &"x".repeat(160)] + .into_iter() + .enumerate() + { for action in ["empty", "paste", "runtime"] { + let prefix = format!("echo pebrel_native_history_{nonce}_{index}_{action}"); + let command = format!("{prefix} echoed"); + let scope = crate::nebula_history::HistoryScope::Local; + assert_eq!(suggest::history_hint_for_test(&scope, &prefix), None); let (view, window, _) = open(cx); view.update(window, |view, cx| { let (session, _input, _events, proxy) = session::test_session_with_events(); @@ -101,15 +110,33 @@ fn custom_native_prompts_handle_empty_submit_paste_and_runtime_without_fake_hist )); match action { "empty" => view.commit_line(cx), - "paste" => view.paste_now_impl("pause\r\n", false, cx), + "paste" => view.paste_now_impl(&format!("{command}\r\n"), false, cx), _ => { - view.runtime_prompt("pause".into(), true, cx).unwrap(); + view.runtime_prompt(command.clone(), true, cx).unwrap(); }, } assert_eq!(view.command_running, action != "empty", "{prompt:?} {action}"); - assert!(view.suggest.last_committed.is_empty(), "unconfirmed input is not history"); + // Runtime keeps the submitted program identity before its echo + // barrier. Persistent history must still wait for screen input. + let identity = if action == "runtime" { command.as_str() } else { "" }; + assert_eq!(view.suggest.last_committed, identity, "{prompt:?} {action}"); + assert_eq!( + suggest::history_hint_for_test(&scope, &prefix), + None, + "unconfirmed input is not history: {prompt:?} {action}" + ); if action != "empty" { assert!(view.suggest.pending_command_prompt.is_some()); + } else { + // Positive control reads the same history owner after real + // terminal echo and Enter, including pending-wrap prompts. + feed(view, command.as_bytes()); + view.commit_line(cx); + assert_eq!(view.suggest.last_committed, command); + assert_eq!( + suggest::history_hint_for_test(&scope, &prefix).as_deref(), + Some(" echoed") + ); } }); }