magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::super::*;
use super::support::*;
use std::time::Instant;

#[test]
fn immutable_key_classifier_emits_prompt_edit_without_mutating_state() {
    let state = MissionControlState {
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_editor: crate::tui::state::PromptEditor::new("ab", 2),
        ..Default::default()
    };
    let before = (
        state.prompt_plain_text(),
        state.prompt_cursor(),
        state.prompt_content_revision(),
        state.focus_pane,
    );
    let command = classify_key_at(
        key(KeyCode::Char('x')),
        &state,
        KeyViewports {
            prompt: Some(PromptViewport {
                visible_rows: 3,
                wrap_width: 20,
            }),
            ..KeyViewports::default()
        },
        &[],
        Instant::now(),
    );
    let (_, display) = command.into_parts();
    let Some(DisplayCommand::Batch(commands)) = display else {
        panic!("expected standalone-control prefix and prompt command");
    };
    assert!(matches!(
        commands.last(),
        Some(DisplayCommand::Prompt(PromptCommand::Edit {
            operation: PromptEditCommand::InsertChar('x'),
            refresh_autocomplete: true,
            ..
        }))
    ));
    assert_eq!(
        (
            state.prompt_plain_text(),
            state.prompt_cursor(),
            state.prompt_content_revision(),
            state.focus_pane,
        ),
        before
    );
}

#[test]
fn immutable_paste_classifier_emits_insert_without_mutating_state() {
    let state = MissionControlState {
        focus_pane: crate::tui::state::TuiFocusPane::Prompt,
        prompt_editor: crate::tui::state::PromptEditor::new("/", 1),
        ..Default::default()
    };
    let before = (state.prompt_plain_text(), state.prompt_cursor());
    let command = classify_paste_with_all_viewports(
        "new",
        &state,
        KeyViewports {
            prompt: Some(PromptViewport {
                visible_rows: 2,
                wrap_width: 16,
            }),
            ..KeyViewports::default()
        },
        &[],
    );
    assert!(matches!(
        command,
        InputCommand::Display(DisplayCommand::Prompt(PromptCommand::InsertText {
            text,
            refresh_autocomplete: true,
            viewport: PromptViewport {
                visible_rows: 2,
                wrap_width: 16,
            },
        })) if text == "new"
    ));
    assert_eq!((state.prompt_plain_text(), state.prompt_cursor()), before);
}

#[test]
fn immutable_modal_classifier_emits_close_without_mutating_state() {
    let mut state = MissionControlState::default();
    state.open_system_prompt_modal("system prompt".to_string());
    let before = (
        state.system_prompt_modal_visible(),
        state.focus_pane,
        state.status.clone(),
    );
    let command = classify_key_at(
        key(KeyCode::Esc),
        &state,
        KeyViewports::default(),
        &[],
        Instant::now(),
    );
    let (_, display) = command.into_parts();
    let Some(DisplayCommand::Batch(commands)) = display else {
        panic!("expected standalone-control prefix and modal command");
    };
    assert!(matches!(
        commands.last(),
        Some(DisplayCommand::Modal(ModalCommand::CloseSystemPrompt))
    ));
    assert_eq!(
        (
            state.system_prompt_modal_visible(),
            state.focus_pane,
            state.status,
        ),
        before
    );
}

#[test]
fn immutable_mouse_classifier_emits_click_without_mutating_state() {
    let area = ratatui::layout::Rect::new(0, 0, 100, 30);
    let state = state_with_activity();
    let activity_area = crate::tui::render::layout_for(area, &state)
        .pane_area(crate::tui::render::TuiPane::ActivityTree)
        .expect("activity pane");
    let text_area = crate::tui::render::content_text_area_for_pane(
        crate::tui::render::TuiPane::ActivityTree,
        activity_area,
    );
    let mouse = crossterm::event::MouseEvent {
        kind: crossterm::event::MouseEventKind::Down(crossterm::event::MouseButton::Left),
        column: text_area.x,
        row: text_area.y,
        modifiers: KeyModifiers::NONE,
    };
    let before = (state.selected, state.focus_pane, state.prompt_plain_text());
    let command = crate::tui::input::mouse::classify_mouse_event(mouse, area, &state, 3)
        .expect("activity click command");
    assert!(matches!(
        command,
        DisplayCommand::Mouse(MouseCommand::ClickActivityTree { .. })
    ));
    assert_eq!(
        (state.selected, state.focus_pane, state.prompt_plain_text()),
        before
    );
}

#[test]
fn production_classifier_and_reducer_apply_prompt_edit_matrix() {
    let viewport = PromptViewport {
        visible_rows: 3,
        wrap_width: 20,
    };
    let cases = [
        (key(KeyCode::Char('x')), "ab", 2, "abx", 3),
        (key(KeyCode::Backspace), "ab", 2, "a", 1),
        (key(KeyCode::Delete), "ab", 1, "a", 1),
        (
            modified_key(KeyCode::Enter, KeyModifiers::SHIFT),
            "ab",
            1,
            "a\nb",
            2,
        ),
    ];

    for (key, initial, cursor, expected, expected_cursor) in cases {
        let mut state = MissionControlState {
            focus_pane: crate::tui::state::TuiFocusPane::Prompt,
            prompt_editor: crate::tui::state::PromptEditor::new(initial, cursor),
            ..Default::default()
        };
        let command = classify_key_with_all_viewports(
            key,
            &state,
            KeyViewports {
                prompt: Some(viewport),
                ..KeyViewports::default()
            },
            &[],
        );
        let (action, display) = command.into_parts();
        assert_eq!(action, InputAction::None);
        let (changed, copy) = crate::tui::controller::apply_display_command_for_test(
            display.expect("classified prompt edit"),
            &mut state,
            &[],
        );

        assert!(changed, "expected prompt edit for {key:?}");
        assert_eq!(copy, None);
        assert_eq!(state.prompt_plain_text(), expected);
        assert_eq!(state.prompt_cursor(), expected_cursor);
    }
}

#[test]
fn subagent_viewer_keys_route_to_bounded_modal_commands() {
    let mut state = MissionControlState::default();
    let batch = ActivityId::new("input-viewer-batch");
    state.apply_activity_event(ActivityEvent::Started {
        id: batch.clone(),
        parent_id: None,
        kind: ActivityKind::SubagentBatch,
        status: ActivityStatus::Running,
        metadata: ActivityMetadata::new("subagents"),
    });
    for task in ["g1", "g2"] {
        state.apply_activity_event(ActivityEvent::Started {
            id: batch.child(task),
            parent_id: Some(batch.clone()),
            kind: ActivityKind::SubagentTask,
            status: ActivityStatus::Running,
            metadata: ActivityMetadata::new(task),
        });
    }
    state.open_subagent_viewer(batch, ActivityId::new("input-viewer-batch/g1"));
    let viewport = SystemPromptViewport {
        visible_rows: 5,
        wrap_width: 40,
    };

    let cases = [
        (KeyCode::Tab, ModalCommand::SubagentViewerSelectNext),
        (KeyCode::Right, ModalCommand::SubagentViewerSelectNext),
        (KeyCode::BackTab, ModalCommand::SubagentViewerSelectPrevious),
        (KeyCode::Left, ModalCommand::SubagentViewerSelectPrevious),
        (KeyCode::Home, ModalCommand::SubagentViewerScrollHome),
    ];
    for (code, expected) in cases {
        let (_, display) = classify_key_at(
            key(code),
            &state,
            KeyViewports {
                subagent_viewer: Some(viewport),
                ..KeyViewports::default()
            },
            &[],
            Instant::now(),
        )
        .into_parts();
        let display = display.expect("viewer display command");
        let actual = match display {
            DisplayCommand::Batch(mut commands) => commands.pop().expect("viewer command"),
            display => display,
        };
        assert_eq!(actual, DisplayCommand::Modal(expected));
    }

    for (code, down, rows) in [
        (KeyCode::Up, false, 1),
        (KeyCode::Down, true, 1),
        (KeyCode::PageUp, false, 5),
        (KeyCode::PageDown, true, 5),
    ] {
        let (_, display) = classify_key_at(
            key(code),
            &state,
            KeyViewports {
                subagent_viewer: Some(viewport),
                ..KeyViewports::default()
            },
            &[],
            Instant::now(),
        )
        .into_parts();
        let display = display.expect("viewer scroll command");
        let actual = match display {
            DisplayCommand::Batch(mut commands) => commands.pop().expect("viewer command"),
            display => display,
        };
        assert_eq!(
            actual,
            DisplayCommand::Scroll(ScrollCommand {
                target: ScrollTarget::SubagentViewer,
                down,
                rows,
                visible_rows: 5,
                wrap_width: 40,
            })
        );
    }

    let (_, display) = classify_key_at(
        key(KeyCode::End),
        &state,
        KeyViewports {
            subagent_viewer: Some(viewport),
            ..KeyViewports::default()
        },
        &[],
        Instant::now(),
    )
    .into_parts();
    assert!(matches!(
        display,
        Some(DisplayCommand::Batch(commands))
            if matches!(commands.last(), Some(DisplayCommand::Modal(ModalCommand::SubagentViewerScrollEnd { viewport: actual })) if *actual == viewport)
    ));
}

#[test]
fn plain_tab_classifier_emits_next_primary_pane_command() {
    let state = MissionControlState::default();
    let (action, display) = classify_key_at(
        key(KeyCode::Tab),
        &state,
        KeyViewports::default(),
        &[],
        Instant::now(),
    )
    .into_parts();

    assert_eq!(action, InputAction::None);
    let Some(DisplayCommand::Batch(commands)) = display else {
        panic!("expected standalone-control prefix and tab command");
    };
    assert!(matches!(
        commands.last(),
        Some(DisplayCommand::Focus(FocusCommand::NextPrimaryPane))
    ));
    assert!(state.is_prompt_focused());
}