mitts 0.3.26

Rust-first build and package tooling with a shared artifact cache
Documentation
/*
 * Mitts Build — build command tests
 * Copyright (c) 2026 Alexander Panasenko
 * Contact: alex@prod.codes
 * Author: https://prod.codes/about/
 * Project: https://github.com/alex09x/mitts
 * SPDX-License-Identifier: MIT OR Apache-2.0
 */
use super::*;
use crate::core::action::{Action, ActionKind, ActionResult, BuildPlan, ToolchainInfo};
use std::collections::HashMap;
use std::path::PathBuf;

#[test]
fn test_progress_callback_all_events() {
    // 1. None (verbose/text mode)
    let cb_none = create_progress_callback(None);
    cb_none.0(BuildProgressEvent::InitTotal {
        total: 5,
        cached: 2,
    });
    cb_none.0(BuildProgressEvent::Compiling("my_crate".to_string()));
    cb_none.0(BuildProgressEvent::UnitFinished);
    cb_none.0(BuildProgressEvent::CompilerMessage("msg".to_string()));
    cb_none.0(BuildProgressEvent::Diagnostic("diag".to_string()));

    // 2. Some (progress bar mode)
    let pb = Ui::create_build_progress("dev");
    let cb_some = create_progress_callback(Some(pb.clone()));
    cb_some.0(BuildProgressEvent::InitTotal {
        total: 5,
        cached: 2,
    });
    cb_some.0(BuildProgressEvent::Compiling("my_crate".to_string()));
    cb_some.0(BuildProgressEvent::UnitFinished);
    cb_some.0(BuildProgressEvent::CompilerMessage("msg".to_string()));
    cb_some.0(BuildProgressEvent::Diagnostic("diag".to_string()));
    pb.finish_and_clear();
}

#[test]
fn test_render_build_result_branches() {
    let dummy_tc = ToolchainInfo {
        name: "rustc".to_string(),
        version: "1.80.0".to_string(),
        target_triple: None,
    };
    let make_action = |id: &str, kind: ActionKind| Action {
        id: id.to_string(),
        kind,
        description: format!("action {}", id),
        toolchain: dummy_tc.clone(),
        inputs: Vec::new(),
        outputs: vec![PathBuf::from(format!("/out/{}", id))],
        args: Vec::new(),
        env: HashMap::new(),
        dependencies: Vec::new(),
    };

    let now = std::time::Instant::now();

    // 1. Fast lock hit
    let plan_fast = BuildPlan {
        actions: vec![make_action("root-bin", ActionKind::CompileBin)],
        target_directory: PathBuf::from("/target"),
        artifacts: Default::default(),
        unit_cfgs: Default::default(),
        ..Default::default()
    };
    let res_fast = ActionResult {
        action_id: "fast-lock-hit".to_string(),
        exit_code: 0,
        success: true,
        stdout: String::new(),
        stderr: String::new(),
        cached: true,
    };
    assert_eq!(
        render_build_result(&plan_fast, &res_fast, "dev", now, false),
        0
    );

    // 2. Cached non-fast-lock
    let res_cached = ActionResult {
        action_id: "ac-hit".to_string(),
        exit_code: 0,
        success: true,
        stdout: String::new(),
        stderr: String::new(),
        cached: true,
    };
    assert_eq!(
        render_build_result(&plan_fast, &res_cached, "dev", now, false),
        0
    );

    // 3. actions <= 3 executed
    let res_exec = ActionResult {
        action_id: "exec".to_string(),
        exit_code: 0,
        success: true,
        stdout: String::new(),
        stderr: String::new(),
        cached: false,
    };
    assert_eq!(
        render_build_result(&plan_fast, &res_exec, "dev", now, false),
        0
    );

    // 4. actions > 3 executed with root bin
    let plan_many = BuildPlan {
        actions: vec![
            make_action("dep1", ActionKind::CompileRlib),
            make_action("dep2", ActionKind::CompileRlib),
            make_action("dep3", ActionKind::CompileRlib),
            make_action("root", ActionKind::CompileBin),
        ],
        target_directory: PathBuf::from("/target"),
        artifacts: Default::default(),
        unit_cfgs: Default::default(),
        ..Default::default()
    };
    assert_eq!(
        render_build_result(&plan_many, &res_exec, "dev", now, false),
        0
    );

    // 5. actions > 3 without root bin
    let plan_libs = BuildPlan {
        actions: vec![
            make_action("dep1", ActionKind::CompileRlib),
            make_action("dep2", ActionKind::CompileRlib),
            make_action("dep3", ActionKind::CompileRlib),
            make_action("dep4", ActionKind::CompileRlib),
        ],
        target_directory: PathBuf::from("/target"),
        artifacts: Default::default(),
        unit_cfgs: Default::default(),
        ..Default::default()
    };
    assert_eq!(
        render_build_result(&plan_libs, &res_exec, "dev", now, false),
        0
    );

    // 6. failure
    let res_fail = ActionResult {
        action_id: "fail".to_string(),
        exit_code: 101,
        success: false,
        stdout: String::new(),
        stderr: "error: test failure\n".to_string(),
        cached: false,
    };
    assert_eq!(
        render_build_result(&plan_fast, &res_fail, "dev", now, true),
        101
    );
}