magi-code 0.77.1

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

#[test]
fn submit_new_rejects_while_provider_run_active() {
    let temp = tempfile::TempDir::new().unwrap();
    let (sender, receiver) = bounded::<TuiEvent>(4);
    let mut app = test_app(&temp, sender);
    app.active_run = true;
    let mut ui_state = state::MissionControlState::default();

    app.submit("/new".to_string(), &mut ui_state, &receiver, test_area());

    assert!(app.state.current_session.is_none());
    assert_eq!(
        ui_state.status,
        "cannot start a new session while a prompt is running"
    );
    assert!(receiver.try_recv().is_err());
}

#[test]
fn submit_new_preserves_queued_controller_events_for_centralized_drain() {
    let temp = tempfile::TempDir::new().unwrap();
    let (sender, receiver) = bounded::<TuiEvent>(8);
    let mut app = test_app(&temp, sender.clone());
    let mut ui_state = state::MissionControlState {
        ..Default::default()
    };
    ui_state.apply_output_event(&OutputEvent::UserPrompt {
        text: "visible old".to_string(),
    });
    ui_state.apply_activity_event(ActivityEvent::Started {
        id: crate::output::ActivityId::new("visible-old-tool"),
        parent_id: None,
        kind: crate::output::ActivityKind::Tool,
        status: crate::output::ActivityStatus::Running,
        metadata: crate::output::ActivityMetadata::new("visible old tool"),
    });
    sender
        .send(TuiEvent::Output(OutputEvent::UserPrompt {
            text: "queued old".to_string(),
        }))
        .unwrap();
    sender
        .send(TuiEvent::Activity(ActivityEvent::Started {
            id: crate::output::ActivityId::new("queued-old-tool"),
            parent_id: None,
            kind: crate::output::ActivityKind::Tool,
            status: crate::output::ActivityStatus::Running,
            metadata: crate::output::ActivityMetadata::new("queued old tool"),
        }))
        .unwrap();
    sender.send(TuiEvent::Done).unwrap();
    sender
        .send(TuiEvent::RunFinished {
            worker_id: 0,
            final_event: None,
        })
        .unwrap();

    app.submit(
        "  /new  ".to_string(),
        &mut ui_state,
        &receiver,
        test_area(),
    );
    let status = ui_state.status.clone();
    assert_eq!(receiver.len(), 4);

    assert!(status.starts_with("new session: "));
    assert_eq!(ui_state.status, status);
    assert!(ui_state.transcript.is_empty());
    assert_eq!(ui_state.selected_activity_text(), "No activity selected.");
    assert!(ui_state.nodes.is_empty());
    assert_eq!(ui_state.help_offset(), 0);
    assert!(app.state.current_session.is_some());
    assert!(app.worker.is_none());
    assert!(!app.active_run);
}

#[test]
fn submit_new_with_args_resets_ui_and_creates_no_worker() {
    let temp = tempfile::TempDir::new().unwrap();
    let (sender, receiver) = bounded::<TuiEvent>(4);
    let mut app = test_app(&temp, sender);
    let mut ui_state = state::MissionControlState::default();
    ui_state.apply_output_event(&OutputEvent::UserPrompt {
        text: "old".to_string(),
    });

    app.submit(
        "/new extra".to_string(),
        &mut ui_state,
        &receiver,
        test_area(),
    );

    assert!(ui_state.status.starts_with("new session: "));
    assert!(ui_state.transcript.is_empty());
    assert!(app.state.current_session.is_some());
    assert!(app.worker.is_none());
    assert!(!app.active_run);
    let drained = drain_tui_events(&receiver, &mut ui_state);
    assert!(!drained.changed);
    assert!(!drained.run_finished);
}

#[test]
fn submit_quit_with_args_creates_no_worker() {
    let temp = tempfile::TempDir::new().unwrap();
    let (sender, receiver) = bounded::<TuiEvent>(4);
    let mut app = test_app(&temp, sender);
    let mut ui_state = state::MissionControlState::default();

    app.submit(
        "/quit extra".to_string(),
        &mut ui_state,
        &receiver,
        test_area(),
    );

    assert!(app.worker.is_none());
    assert!(!app.active_run);
    assert!(receiver.try_recv().is_err());
}

#[test]
fn submit_invalid_model_command_reports_error_and_creates_no_worker() {
    let temp = tempfile::TempDir::new().unwrap();
    let manager = SessionManager::new(temp.path().join("sessions"));
    let session = manager.create().unwrap();
    let (sender, receiver) = bounded::<TuiEvent>(4);
    let mut app = test_app_with_active_session(&temp, sender, Some(session.clone()));
    let mut ui_state = state::MissionControlState {
        provider: "openai".to_string(),
        model: "test-model".to_string(),
        ..Default::default()
    };

    app.submit(
        "/setmodel gpt-next".to_string(),
        &mut ui_state,
        &receiver,
        test_area(),
    );
    reap_model_selection_worker(&mut app, &mut ui_state, &receiver);

    assert_eq!(
        ui_state.status,
        "model id must use provider/model-name format"
    );
    assert!(receiver.try_recv().is_err());
    assert!(app.worker.is_none());
    assert!(!app.active_run);
    let events = session.read_events().unwrap();
    assert_eq!(events.len(), 1);
    assert_eq!(events[0].event_type, "diagnostic");
    assert_eq!(
        events[0].payload["message"],
        "model id must use provider/model-name format"
    );
}