ek-ui 0.2.4

ek 生态常驻主界面(egui/eframe):插件即界面——观测页 + 日志页,车头与 UI 同插件
Documentation
//! L3:pick 窗 kittest(勾选翻位 / 摘要联动 / 启钮禁用-触发 / 取消钮)。
//!
//! 启动动作经回调注入(不真 spawn;进程线全链在 tests/launch.rs + bin 手跑面)。

use egui_kittest::{Harness, kittest::Queryable};
use ek_ui::launcher_ui::{BTN_CANCEL, BTN_LAUNCH, pick_kinds, render_pick};

fn kinds() -> Vec<(String, String)> {
    pick_kinds()
}

#[test]
fn m0_toggle_rows_and_summary() {
    let kinds = kinds();
    let kind0 = kinds[0].0.clone(); // 表首 = dm(缺省表序)
    let sel = vec![false; kinds.len()];

    let mut harness = Harness::new_ui_state(
        move |ui, sel: &mut Vec<bool>| {
            let k = kinds.clone();
            render_pick(ui, sel, &k, &mut || {}, &mut || {});
        },
        sel,
    );

    // 初始:无选中(摘要 = 无)。
    assert!(harness.query_by_label_contains("(无)").is_some());
    // 勾 dm → 摘要变化 + 状态位翻真。
    harness.get_by_label("dm").click();
    harness.run();
    assert!(harness.state().iter().any(|&b| b), "dm checkbox state");
    assert!(harness.query_by_label_contains("已选: dm").is_some());

    // 再勾 oms → 两项。
    harness.get_by_label("oms").click();
    harness.run();
    assert!(harness.query_by_label_contains("已选: dm, oms").is_some());
    assert_eq!(harness.state().iter().filter(|&&b| b).count(), 2);

    // 翻掉 dm 再只剩 oms。
    harness.get_by_label("dm").click();
    harness.run();
    assert!(harness.query_by_label_contains("已选: oms").is_some());
    assert_eq!(harness.state().iter().filter(|&&b| b).count(), 1);
    let _ = &kind0;
}

#[test]
fn m1_launch_button_disabled_then_fires() {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicBool, Ordering};

    let kinds = kinds();
    let fired = Arc::new(AtomicBool::new(false));
    let fired_cap = Arc::clone(&fired);
    let cancelled = Arc::new(AtomicBool::new(false));
    let cancelled_cap = Arc::clone(&cancelled);
    let sel = vec![false; kinds.len()];
    let kinds_owned = kinds.clone();

    let mut harness = Harness::new_ui_state(
        move |ui, sel: &mut Vec<bool>| {
            let k = kinds_owned.clone();
            render_pick(
                ui,
                sel,
                &k,
                &mut || fired_cap.store(true, Ordering::Release),
                &mut || cancelled_cap.store(true, Ordering::Release),
            );
        },
        sel,
    );

    // 空选:启动钮禁用 → 点击不触发。
    harness.get_by_label(BTN_LAUNCH).click();
    harness.run();
    assert!(
        !fired.load(Ordering::Acquire),
        "disabled launch must not fire"
    );
    assert!(!cancelled.load(Ordering::Acquire));

    // 勾 oms → 启动钮可点 → 回调真实发生(取消钮同应)。
    harness.get_by_label("oms").click();
    harness.run();
    harness.get_by_label(BTN_LAUNCH).click();
    harness.run();
    assert!(
        fired.load(Ordering::Acquire),
        "launch callback must fire after selection"
    );
}

#[test]
fn m2_cancel_button_always_active() {
    let kinds = kinds();
    let sel = vec![false; kinds.len()];
    let kinds_owned = kinds.clone();
    let mut harness = Harness::new_ui_state(
        move |ui, sel: &mut Vec<bool>| {
            let k = kinds_owned.clone();
            render_pick(ui, sel, &k, &mut || {}, &mut || {});
        },
        sel,
    );
    assert!(harness.query_by_label(BTN_CANCEL).is_some());
    harness.run(); // 无 panic
}