magi-code 0.64.0

Repository-aware CLI coding agent for terminal work
Documentation
use super::*;

#[test]
fn render_skill_autocomplete_popup_title_and_rows() {
    let mut state = MissionControlState {
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        input: "$ru".to_string(),
        prompt_cursor: 3,
        ..Default::default()
    };
    state.autocomplete = Some(crate::tui::state::AutocompleteState {
        candidates: vec![crate::tui::state::AutocompleteCandidate::skill_tag(
            "rust-dev",
        )],
        selected: 0,
        token_start: 0,
        token_end: 3,
        token: "$ru".to_string(),
    });
    let backend = TestBackend::new(80, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();

    terminal.draw(|frame| draw(frame, &state)).unwrap();

    let rendered = terminal
        .backend()
        .buffer()
        .content()
        .iter()
        .map(|cell| cell.symbol())
        .collect::<String>();
    assert!(rendered.contains("Skill tags"), "{rendered}");
    assert!(rendered.contains("$rust-dev"), "{rendered}");
    assert!(rendered.contains("skill"), "{rendered}");
}

#[test]
fn render_prompt_shows_provider_model_and_thinking_on_bottom_right_border() {
    let mut state = MissionControlState {
        provider: "openai-codex".to_string(),
        model: "gpt-5.5".to_string(),
        provider_ready: true,
        thinking_levels: crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
        ..Default::default()
    };
    state.refresh_thinking_levels(
        crate::thinking::ThinkingLevel::High,
        state.thinking_levels.clone(),
    );
    let backend = TestBackend::new(100, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    let metadata = find_text(buffer, " • openai-codex • gpt-5.5 • Thinking: High [Alt-T]").unwrap();
    let alt_t = find_text(buffer, "[Alt-T]").unwrap();
    let layout = layout_for(Rect::new(0, 0, 100, 20), &state);

    assert_eq!(metadata.1, layout.prompt.y + layout.prompt.height - 1);
    assert!(alt_t.0 > layout.prompt.x + layout.prompt.width / 2);
}

#[test]
fn render_prompt_shows_alt_m_hint_when_idle() {
    let mut state = MissionControlState {
        provider: "zai".to_string(),
        model: "glm-5.2".to_string(),
        provider_ready: true,
        thinking_levels: crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
        ..Default::default()
    };
    state.refresh_thinking_levels(
        crate::thinking::ThinkingLevel::High,
        state.thinking_levels.clone(),
    );
    let backend = TestBackend::new(100, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    assert!(
        find_text(buffer, "[Alt-M]").is_some(),
        "Alt-M hint should show when idle"
    );
    let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
    let hint = find_text(buffer, "[Alt-M]").unwrap();
    assert_eq!(hint.1, layout.prompt.y + layout.prompt.height - 1);
}

#[test]
fn render_prompt_hides_alt_m_hint_while_running() {
    let mut state = MissionControlState {
        provider: "zai".to_string(),
        model: "glm-5.2".to_string(),
        provider_ready: true,
        thinking_levels: crate::thinking::ThinkingLevel::EFFORT_GENERIC.to_vec(),
        ..Default::default()
    };
    state.refresh_thinking_levels(
        crate::thinking::ThinkingLevel::High,
        state.thinking_levels.clone(),
    );
    state.start_running_prompt("inspect".to_string());
    let backend = TestBackend::new(100, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    assert!(
        find_text(buffer, "[Alt-M]").is_none(),
        "Alt-M hint should hide while running"
    );
}

#[test]
fn render_running_status_and_cancel_hint_on_prompt_top_left_only() {
    let mut state = MissionControlState {
        status: "running prompt…".to_string(),
        provider_ready: true,
        ..Default::default()
    };
    state.start_running_prompt("inspect".to_string());
    let backend = TestBackend::new(100, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();

    terminal.draw(|frame| draw(frame, &state)).unwrap();

    let buffer = terminal.backend().buffer();
    let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
    let status = find_text_in_area(buffer, layout.prompt, "running prompt…").expect("status");
    let cancel = find_text_in_area(buffer, layout.prompt, "[Alt-C]").expect("cancel hint");

    assert_eq!(status.1, layout.prompt.y);
    assert_eq!(cancel.1, layout.prompt.y);
    assert!(status.0 < layout.prompt.x + layout.prompt.width / 2);
    let transcript = rendered_text_in_area(buffer, layout.transcript);
    assert!(!transcript.contains("run ◐"), "{transcript}");
    assert!(!transcript.contains("running prompt…"), "{transcript}");
    assert!(!transcript.contains("[Alt-C]"), "{transcript}");
}

#[test]
fn render_prompt_shows_pending_steering_count_on_top_left_border() {
    let state = MissionControlState {
        pending_steering_count: 3,
        provider_ready: true,
        ..Default::default()
    };
    let backend = TestBackend::new(100, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    let layout = layout_for(Rect::new(0, 0, 100, 20), &state);
    let queued = find_text_in_area(buffer, layout.prompt, "3 steering queued").expect("queued");

    assert_eq!(queued.1, layout.prompt.y);
    let transcript = rendered_text_in_area(buffer, layout.transcript);
    assert!(!transcript.contains("3 steering queued"), "{transcript}");
}

#[test]
fn render_prompt_hides_pending_steering_count_when_clear() {
    let state = MissionControlState {
        pending_steering_count: 0,
        provider_ready: true,
        ..Default::default()
    };
    let backend = TestBackend::new(100, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let rendered = terminal
        .backend()
        .buffer()
        .content()
        .iter()
        .map(|cell| cell.symbol())
        .collect::<String>();

    assert!(!rendered.contains("steering queued"));
}

#[test]
fn render_shows_block_prompt_cursor_when_prompt_focused() {
    let mut state = MissionControlState {
        input: "hello".to_string(),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_cursor_visible: true,
        ..Default::default()
    };
    let backend = TestBackend::new(80, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    assert!(find_text(buffer, "hello").is_some());
    assert!(find_text(buffer, "").is_some());
    assert!(find_text(buffer, "").is_none());

    state.prompt_cursor_visible = false;
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let blink_off_buffer = terminal.backend().buffer();
    assert!(find_text(blink_off_buffer, "hello").is_some());
    assert!(find_text(blink_off_buffer, "").is_none());

    state.focus_activity_tree();
    state.prompt_cursor_visible = true;
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let activity_focus_buffer = terminal.backend().buffer();
    assert!(find_text(activity_focus_buffer, "hello").is_some());
    assert!(find_text(activity_focus_buffer, "").is_none());
}

#[test]
fn render_places_prompt_cursor_at_logical_position() {
    let state = MissionControlState {
        input: "abcd".to_string(),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_cursor_visible: true,
        prompt_cursor: 2,
        ..Default::default()
    };
    let backend = TestBackend::new(40, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    let prompt_area = layout_for(Rect::new(0, 0, 40, 20), &state).prompt;
    let text_area = content_text_area_for_pane(TuiPane::Prompt, prompt_area);

    let ab = find_text_in_area(buffer, text_area, "ab").unwrap();
    let cursor = find_text_in_area(buffer, text_area, "").unwrap();
    let cd = find_text_in_area(buffer, text_area, "cd").unwrap();
    assert_eq!(ab.1, cursor.1);
    assert_eq!(cursor.1, cd.1);
    assert!(ab.0 < cursor.0 && cursor.0 < cd.0);
}

#[test]
fn render_prompt_preserves_explicit_newlines_with_cursor_styling() {
    let state = MissionControlState {
        input: "ALPHA\nBETA".to_string(),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_cursor_visible: true,
        prompt_cursor: "ALPHA\nBE".len(),
        ..Default::default()
    };
    let backend = TestBackend::new(80, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();
    let prompt_area = layout_for(Rect::new(0, 0, 80, 20), &state).prompt;

    let alpha = find_text_in_area(buffer, prompt_area, "ALPHA").unwrap();
    let be = find_text_in_area(buffer, prompt_area, "BE").unwrap();
    let cursor = find_text_in_area(buffer, prompt_area, "").unwrap();
    let ta = find_text_in_area(buffer, prompt_area, "TA").unwrap();

    assert_eq!(be.1, alpha.1 + 1);
    assert_eq!(cursor.1, be.1);
    assert_eq!(ta.1, be.1);
    assert!(be.0 < cursor.0 && cursor.0 < ta.0);
    assert_eq!(buffer[cursor].fg, MATRIX_GREEN.green_neon);
    assert_eq!(buffer[cursor].bg, MATRIX_GREEN.background);
    assert_eq!(buffer[alpha].fg, MATRIX_GREEN.text);
    assert_eq!(buffer[be].fg, MATRIX_GREEN.text);
    assert_eq!(buffer[ta].fg, MATRIX_GREEN.text);
}

#[test]
fn render_prompt_can_show_start_after_cursor_auto_reveal() {
    let mut state = MissionControlState {
        input: format!("HEAD{}TAIL", "x".repeat(130)),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_cursor_visible: true,
        prompt_cursor: 0,
        ..Default::default()
    };
    state.ensure_prompt_cursor_visible(5, 16);
    let backend = TestBackend::new(20, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let rendered = terminal
        .backend()
        .buffer()
        .content()
        .iter()
        .map(|cell| cell.symbol())
        .collect::<String>();

    assert!(rendered.contains("HEAD"));
    assert!(!rendered.contains("TAIL"));
}

#[test]
fn render_prompt_tails_overflow_after_five_wrapped_rows() {
    let mut state = MissionControlState {
        input: format!("HEAD{}TAIL", "x".repeat(75)),
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_cursor_visible: true,
        ..Default::default()
    };
    state.prompt_cursor = state.input.len();
    state.ensure_prompt_cursor_visible(5, 14);
    let backend = TestBackend::new(20, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let rendered = terminal
        .backend()
        .buffer()
        .content()
        .iter()
        .map(|cell| cell.symbol())
        .collect::<String>();

    assert!(rendered.contains("TAIL"));
    assert!(!rendered.contains("HEAD"));
}

#[test]
fn render_autocomplete_popup_when_visible() {
    let state = state_with_autocomplete();
    let backend = TestBackend::new(80, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let rendered = terminal
        .backend()
        .buffer()
        .content()
        .iter()
        .map(|cell| cell.symbol())
        .collect::<String>();
    assert!(rendered.contains("Slash commands"));
    assert!(rendered.contains("/new"));
    assert!(rendered.contains("start a new session"));
}

#[test]
fn render_autocomplete_popup_uses_themed_background_and_selection() {
    let mut state = MissionControlState {
        input: "/".to_string(),
        prompt_cursor: 1,
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        ..Default::default()
    };
    state.recompute_autocomplete(&[
        crate::tui::state::AutocompleteCandidate::slash_command("new", "start a new session"),
        crate::tui::state::AutocompleteCandidate::slash_command("quit", "exit magi-code"),
    ]);
    let backend = TestBackend::new(80, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let buffer = terminal.backend().buffer();

    let title = find_text(buffer, "Slash commands").unwrap();
    assert_eq!(buffer[title].fg, MATRIX_GREEN.green_neon);
    assert_eq!(buffer[title].bg, MATRIX_GREEN.panel_alt);

    let selected = find_text(buffer, "/new").unwrap();
    assert_eq!(buffer[selected].fg, MATRIX_GREEN.text);
    assert_eq!(buffer[selected].bg, MATRIX_GREEN.selection);

    let description = find_text(buffer, "start a new session").unwrap();
    assert_eq!(buffer[description].fg, MATRIX_GREEN.text);
    assert_eq!(buffer[description].bg, MATRIX_GREEN.selection);

    let unselected = find_text(buffer, "/quit").unwrap();
    assert_eq!(buffer[unselected].fg, MATRIX_GREEN.green_bright);
    assert_eq!(buffer[unselected].bg, MATRIX_GREEN.panel_alt);
}

#[test]
fn render_autocomplete_popup_absent_when_hidden() {
    let state = MissionControlState::default();
    let backend = TestBackend::new(80, 20);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
    let rendered = terminal
        .backend()
        .buffer()
        .content()
        .iter()
        .map(|cell| cell.symbol())
        .collect::<String>();
    assert!(!rendered.contains("Slash commands"));
}

#[test]
fn render_autocomplete_small_terminal_does_not_panic() {
    let state = state_with_autocomplete();
    let backend = TestBackend::new(12, 5);
    let mut terminal = ratatui::Terminal::new(backend).unwrap();
    terminal.draw(|frame| draw(frame, &state)).unwrap();
}