use chrono::{Duration as ChronoDuration, Utc};
use rch_common::fleet_diff::WorkerObservation;
use rch_common::remediation_view::{
DiskLevel, JobsInput, ProofQueueInput, RemediationView, RemediationWorkerRow, assemble,
build_inputs,
};
use std::collections::VecDeque;
use std::path::PathBuf;
use std::time::Duration;
use tracing::debug;
use super::state::{
ActiveBuild, BuildProgress, BuildStatus, CircuitState, ColorBlindMode, DaemonState,
FilterState, HistoricalBuild, LogViewState, Panel, Status, TuiState, WorkerState, WorkerStatus,
};
pub fn mock_worker(id: &str) -> WorkerState {
debug!("TEST DATA: creating mock worker '{}'", id);
WorkerState {
id: id.to_string(),
host: format!("{}.local", id),
status: WorkerStatus::Healthy,
circuit: CircuitState::Closed,
total_slots: 8,
used_slots: 1,
latency_ms: 10,
last_seen: Utc::now(),
builds_completed: 0,
}
}
pub fn mock_worker_with_status(
id: &str,
status: WorkerStatus,
circuit: CircuitState,
) -> WorkerState {
debug!(
"TEST DATA: creating mock worker '{}' status={:?} circuit={:?}",
id, status, circuit
);
WorkerState {
id: id.to_string(),
host: format!("{}.local", id),
status,
circuit,
total_slots: 8,
used_slots: 2,
latency_ms: 15,
last_seen: Utc::now(),
builds_completed: 5,
}
}
pub fn mock_worker_with_slots(id: &str, used_slots: u32, total_slots: u32) -> WorkerState {
debug!(
"TEST DATA: creating mock worker '{}' slots={}/{}",
id, used_slots, total_slots
);
WorkerState {
id: id.to_string(),
host: format!("{}.local", id),
status: WorkerStatus::Healthy,
circuit: CircuitState::Closed,
total_slots,
used_slots,
latency_ms: 10,
last_seen: Utc::now(),
builds_completed: 0,
}
}
pub fn mock_worker_with_host(id: &str, host: &str) -> WorkerState {
WorkerState {
id: id.to_string(),
host: host.to_string(),
status: WorkerStatus::Healthy,
circuit: CircuitState::Closed,
total_slots: 8,
used_slots: 0,
latency_ms: 10,
last_seen: Utc::now(),
builds_completed: 0,
}
}
pub fn mock_active_build(id: &str, command: &str) -> ActiveBuild {
debug!(
"TEST DATA: creating mock active build '{}' cmd='{}'",
id, command
);
ActiveBuild {
id: id.to_string(),
command: command.to_string(),
worker: Some("worker-1".to_string()),
started_at: Utc::now(),
progress: Some(BuildProgress {
phase: "compiling".to_string(),
percent: Some(50),
current_file: None,
}),
status: BuildStatus::Compiling,
}
}
pub fn mock_active_build_with_status(
id: &str,
command: &str,
status: BuildStatus,
progress_percent: Option<u8>,
) -> ActiveBuild {
debug!(
"TEST DATA: creating mock active build '{}' status={:?} progress={:?}",
id, status, progress_percent
);
ActiveBuild {
id: id.to_string(),
command: command.to_string(),
worker: Some("worker-1".to_string()),
started_at: Utc::now(),
progress: progress_percent.map(|p| BuildProgress {
phase: format!("{:?}", status).to_lowercase(),
percent: Some(p),
current_file: None,
}),
status,
}
}
pub fn mock_active_build_with_worker(id: &str, command: &str, worker_id: &str) -> ActiveBuild {
ActiveBuild {
id: id.to_string(),
command: command.to_string(),
worker: Some(worker_id.to_string()),
started_at: Utc::now(),
progress: Some(BuildProgress {
phase: "compiling".to_string(),
percent: Some(50),
current_file: None,
}),
status: BuildStatus::Compiling,
}
}
pub fn mock_pending_build(id: &str, command: &str) -> ActiveBuild {
ActiveBuild {
id: id.to_string(),
command: command.to_string(),
worker: None,
started_at: Utc::now(),
progress: None,
status: BuildStatus::Pending,
}
}
pub fn mock_historical_build(
id: &str,
command: &str,
worker: Option<&str>,
success: bool,
) -> HistoricalBuild {
debug!(
"TEST DATA: creating mock history '{}' worker={:?} success={}",
id, worker, success
);
let started_at = Utc::now() - ChronoDuration::seconds(5);
let completed_at = Utc::now();
HistoricalBuild {
id: id.to_string(),
command: command.to_string(),
worker: worker.map(|w| w.to_string()),
started_at,
completed_at,
duration_ms: 5000,
success,
exit_code: Some(if success { 0 } else { 1 }),
}
}
pub fn mock_historical_build_with_duration(
id: &str,
command: &str,
duration_ms: u64,
success: bool,
) -> HistoricalBuild {
debug!(
"TEST DATA: creating mock history '{}' duration={}ms success={}",
id, duration_ms, success
);
let started_at = Utc::now() - ChronoDuration::milliseconds(duration_ms as i64);
let completed_at = Utc::now();
HistoricalBuild {
id: id.to_string(),
command: command.to_string(),
worker: Some("worker-1".to_string()),
started_at,
completed_at,
duration_ms,
success,
exit_code: Some(if success { 0 } else { 1 }),
}
}
pub fn mock_historical_build_with_exit_code(
id: &str,
command: &str,
exit_code: i32,
) -> HistoricalBuild {
let success = exit_code == 0;
let started_at = Utc::now() - ChronoDuration::seconds(3);
HistoricalBuild {
id: id.to_string(),
command: command.to_string(),
worker: Some("worker-1".to_string()),
started_at,
completed_at: Utc::now(),
duration_ms: 3000,
success,
exit_code: Some(exit_code),
}
}
pub fn mock_local_build(id: &str, command: &str, success: bool) -> HistoricalBuild {
mock_historical_build(id, command, None, success)
}
pub fn mock_daemon_running() -> DaemonState {
debug!("TEST DATA: creating mock daemon (running)");
DaemonState {
status: Status::Running,
uptime: Duration::from_secs(3600),
version: "0.1.0-test".to_string(),
config_path: PathBuf::from("/etc/rch/config.toml"),
socket_path: PathBuf::from("/tmp/rch.sock"),
builds_today: 42,
bytes_transferred: 1_000_000,
}
}
pub fn mock_daemon_stopped() -> DaemonState {
debug!("TEST DATA: creating mock daemon (stopped)");
DaemonState {
status: Status::Stopped,
uptime: Duration::ZERO,
version: String::new(),
config_path: PathBuf::new(),
socket_path: PathBuf::from("/tmp/rch.sock"),
builds_today: 0,
bytes_transferred: 0,
}
}
pub fn mock_daemon_error() -> DaemonState {
DaemonState {
status: Status::Error,
uptime: Duration::from_secs(100),
version: "0.1.0-test".to_string(),
config_path: PathBuf::new(),
socket_path: PathBuf::from("/tmp/rch.sock"),
builds_today: 5,
bytes_transferred: 50_000,
}
}
pub fn mock_log_view(build_id: &str, line_count: usize) -> LogViewState {
debug!(
"TEST DATA: creating mock log view '{}' with {} lines",
build_id, line_count
);
let mut lines = VecDeque::with_capacity(line_count);
for i in 0..line_count {
let line = if i % 10 == 0 {
format!(" Compiling crate-{} v1.0.0", i)
} else if i % 15 == 0 {
format!("warning: unused variable `x` in line {}", i)
} else if i % 20 == 0 {
format!("error[E0425]: cannot find value `y` in line {}", i)
} else {
format!("Building [{}/{}] target/debug/lib{}.rlib", i, line_count, i)
};
lines.push_back(line);
}
LogViewState {
build_id: build_id.to_string(),
lines,
scroll_offset: 0,
auto_scroll: true,
}
}
pub fn mock_log_view_empty(build_id: &str) -> LogViewState {
LogViewState {
build_id: build_id.to_string(),
lines: VecDeque::new(),
scroll_offset: 0,
auto_scroll: true,
}
}
pub fn mock_log_view_scrolled(
build_id: &str,
line_count: usize,
scroll_offset: usize,
) -> LogViewState {
let mut view = mock_log_view(build_id, line_count);
view.scroll_offset = scroll_offset;
view.auto_scroll = false;
view
}
pub fn mock_filter_with_query(query: &str) -> FilterState {
FilterState {
query: query.to_string(),
worker_filter: None,
success_only: false,
failed_only: false,
}
}
pub fn mock_filter_with_worker(worker_id: &str) -> FilterState {
FilterState {
query: String::new(),
worker_filter: Some(worker_id.to_string()),
success_only: false,
failed_only: false,
}
}
pub fn mock_filter_success_only() -> FilterState {
FilterState {
query: String::new(),
worker_filter: None,
success_only: true,
failed_only: false,
}
}
pub fn mock_filter_failed_only() -> FilterState {
FilterState {
query: String::new(),
worker_filter: None,
success_only: false,
failed_only: true,
}
}
pub fn mock_state() -> TuiState {
debug!("TEST DATA: creating default mock state");
TuiState::new()
}
pub fn mock_state_with_workers(count: usize) -> TuiState {
debug!("TEST DATA: creating mock state with {} workers", count);
let mut state = TuiState::new();
state.daemon = mock_daemon_running();
state.workers = (0..count)
.map(|i| mock_worker(&format!("worker-{}", i + 1)))
.collect();
state
}
pub fn mock_state_with_builds(worker_count: usize, build_count: usize) -> TuiState {
debug!(
"TEST DATA: creating mock state with {} workers and {} builds",
worker_count, build_count
);
let mut state = mock_state_with_workers(worker_count);
state.active_builds = (0..build_count)
.map(|i| mock_active_build(&format!("build-{}", i + 1), "cargo build"))
.collect();
state
}
pub fn mock_state_with_history(history_count: usize) -> TuiState {
debug!(
"TEST DATA: creating mock state with {} history items",
history_count
);
let mut state = mock_state_with_workers(2);
state.build_history = (0..history_count)
.map(|i| {
mock_historical_build(
&format!("h{}", i + 1),
&format!("cargo build --release ({})", i),
Some("worker-1"),
i % 3 != 0, )
})
.collect();
state
}
pub fn mock_state_complete() -> TuiState {
debug!("TEST DATA: creating complete mock state");
let mut state = TuiState::new();
state.daemon = DaemonState {
status: Status::Running,
uptime: Duration::from_secs(7200),
version: "0.1.0-mock".to_string(),
config_path: PathBuf::from("/etc/rch/config.toml"),
socket_path: PathBuf::from("/tmp/rch.sock"),
builds_today: 25,
bytes_transferred: 500_000_000,
};
state.workers = vec![
mock_worker_with_status("worker-1", WorkerStatus::Healthy, CircuitState::Closed),
mock_worker_with_status("worker-2", WorkerStatus::Degraded, CircuitState::HalfOpen),
mock_worker_with_status("worker-3", WorkerStatus::Draining, CircuitState::Open),
mock_worker_with_slots("worker-4", 7, 8),
];
state.active_builds = vec![
mock_active_build_with_status(
"b1",
"cargo build --release",
BuildStatus::Compiling,
Some(65),
),
mock_active_build_with_status("b2", "cargo test", BuildStatus::Syncing, Some(20)),
];
state.build_history = (0..10)
.map(|i| {
mock_historical_build_with_duration(
&format!("h{}", i + 1),
"cargo test --workspace",
1000 + (i as u64) * 500,
i % 5 != 0,
)
})
.collect();
state
}
pub fn mock_state_with_error(error_msg: &str) -> TuiState {
let mut state = TuiState::new();
state.daemon = mock_daemon_stopped();
state.error = Some(error_msg.to_string());
state
}
pub fn mock_state_with_help() -> TuiState {
let mut state = mock_state_complete();
state.show_help = true;
state
}
pub fn mock_state_filter_mode(query: &str) -> TuiState {
let mut state = mock_state_with_history(10);
state.filter_mode = true;
state.filter = mock_filter_with_query(query);
state
}
pub fn mock_state_with_logs(line_count: usize) -> TuiState {
let mut state = mock_state_complete();
state.log_view = Some(mock_log_view("build-log-test", line_count));
state.selected_panel = Panel::Logs;
state
}
pub fn mock_state_with_panel(panel: Panel) -> TuiState {
let mut state = mock_state_complete();
state.selected_panel = panel;
state.selected_index = 0;
state
}
pub fn mock_state_accessible(high_contrast: bool, color_blind: ColorBlindMode) -> TuiState {
let mut state = mock_state_complete();
state.high_contrast = high_contrast;
state.color_blind = color_blind;
state
}
fn rem_ready_row(id: &str) -> RemediationWorkerRow {
RemediationWorkerRow {
observation: WorkerObservation {
worker_id: id.to_string(),
configured: true,
in_daemon_pool: true,
reachable: true,
admin_disabled: false,
temporarily_bypassed: false,
facts_known: true,
command_admissible: true,
},
disk_level: DiskLevel::Ok,
reclaiming: false,
free_ratio: Some(0.7),
slots_used: 2,
slots_total: 8,
telemetry_known: true,
telemetry_fresh: true,
telemetry_age_secs: Some(5),
recovered_pending_canary: false,
absent_secs: None,
}
}
fn rem_view(
rows: &[RemediationWorkerRow],
jobs: JobsInput,
proof: ProofQueueInput,
) -> RemediationView {
let inputs = build_inputs(rows, jobs, proof, Vec::new(), 300);
assemble(&inputs, 1_700_000_000_000)
}
pub fn mock_remediation_view_healthy() -> RemediationView {
rem_view(
&[
rem_ready_row("css"),
rem_ready_row("ovh-a"),
rem_ready_row("ovh-b"),
],
JobsInput {
active: 1,
queued: 0,
stuck: 0,
},
ProofQueueInput::default(),
)
}
pub fn mock_remediation_view_degraded() -> RemediationView {
let mut bypassed = rem_ready_row("ovh-a");
bypassed.observation.temporarily_bypassed = true;
rem_view(
&[rem_ready_row("css"), bypassed, rem_ready_row("ovh-b")],
JobsInput::default(),
ProofQueueInput::default(),
)
}
pub fn mock_remediation_view_no_admissible() -> RemediationView {
let mut a = rem_ready_row("css");
a.observation.facts_known = false;
let mut b = rem_ready_row("ovh-a");
b.observation.facts_known = false;
rem_view(&[a, b], JobsInput::default(), ProofQueueInput::default())
}
pub fn mock_remediation_view_proof_queued() -> RemediationView {
rem_view(
&[rem_ready_row("css"), rem_ready_row("ovh-a")],
JobsInput::default(),
ProofQueueInput {
queued: 3,
replaying: 1,
..ProofQueueInput::default()
},
)
}
pub fn mock_remediation_view_disk_pressure() -> RemediationView {
let mut crit = rem_ready_row("css");
crit.disk_level = DiskLevel::Critical;
crit.free_ratio = Some(0.02);
rem_view(
&[crit, rem_ready_row("ovh-a")],
JobsInput::default(),
ProofQueueInput::default(),
)
}
pub fn mock_remediation_view_stale_telemetry() -> RemediationView {
let mut stale = rem_ready_row("css");
stale.telemetry_fresh = false;
stale.telemetry_age_secs = Some(1200);
rem_view(
&[stale, rem_ready_row("ovh-a")],
JobsInput::default(),
ProofQueueInput::default(),
)
}
pub fn mock_remediation_view_auto_rejoin_pending() -> RemediationView {
let mut canary = rem_ready_row("css");
canary.observation.temporarily_bypassed = true;
canary.recovered_pending_canary = true;
rem_view(
&[canary, rem_ready_row("ovh-a")],
JobsInput::default(),
ProofQueueInput::default(),
)
}
#[cfg(test)]
mod tests {
use super::*;
use tracing::info;
fn init_test_logging() {
let _ = tracing_subscriber::fmt()
.with_test_writer()
.with_max_level(tracing::Level::DEBUG)
.try_init();
}
#[test]
fn test_mock_worker_basic() {
init_test_logging();
info!("TEST START: test_mock_worker_basic");
let worker = mock_worker("test-1");
assert_eq!(worker.id, "test-1");
assert_eq!(worker.host, "test-1.local");
assert_eq!(worker.status, WorkerStatus::Healthy);
assert_eq!(worker.circuit, CircuitState::Closed);
assert_eq!(worker.total_slots, 8);
assert_eq!(worker.used_slots, 1);
info!("TEST PASS: test_mock_worker_basic");
}
#[test]
fn test_mock_worker_with_status() {
init_test_logging();
info!("TEST START: test_mock_worker_with_status");
let worker = mock_worker_with_status("w1", WorkerStatus::Degraded, CircuitState::HalfOpen);
assert_eq!(worker.status, WorkerStatus::Degraded);
assert_eq!(worker.circuit, CircuitState::HalfOpen);
info!("TEST PASS: test_mock_worker_with_status");
}
#[test]
fn test_mock_worker_with_slots() {
init_test_logging();
info!("TEST START: test_mock_worker_with_slots");
let worker = mock_worker_with_slots("w1", 5, 16);
assert_eq!(worker.used_slots, 5);
assert_eq!(worker.total_slots, 16);
info!("TEST PASS: test_mock_worker_with_slots");
}
#[test]
fn test_mock_worker_with_host() {
init_test_logging();
info!("TEST START: test_mock_worker_with_host");
let worker = mock_worker_with_host("w1", "192.168.1.100");
assert_eq!(worker.host, "192.168.1.100");
info!("TEST PASS: test_mock_worker_with_host");
}
#[test]
fn test_mock_active_build_basic() {
init_test_logging();
info!("TEST START: test_mock_active_build_basic");
let build = mock_active_build("b1", "cargo build");
assert_eq!(build.id, "b1");
assert_eq!(build.command, "cargo build");
assert_eq!(build.status, BuildStatus::Compiling);
assert!(build.worker.is_some());
assert!(build.progress.is_some());
info!("TEST PASS: test_mock_active_build_basic");
}
#[test]
fn test_mock_active_build_with_status() {
init_test_logging();
info!("TEST START: test_mock_active_build_with_status");
let build = mock_active_build_with_status("b1", "cmd", BuildStatus::Syncing, Some(30));
assert_eq!(build.status, BuildStatus::Syncing);
assert_eq!(build.progress.as_ref().unwrap().percent, Some(30));
info!("TEST PASS: test_mock_active_build_with_status");
}
#[test]
fn test_mock_pending_build() {
init_test_logging();
info!("TEST START: test_mock_pending_build");
let build = mock_pending_build("b1", "cargo test");
assert_eq!(build.status, BuildStatus::Pending);
assert!(build.worker.is_none());
assert!(build.progress.is_none());
info!("TEST PASS: test_mock_pending_build");
}
#[test]
fn test_mock_historical_build_success() {
init_test_logging();
info!("TEST START: test_mock_historical_build_success");
let build = mock_historical_build("h1", "cargo build", Some("w1"), true);
assert_eq!(build.id, "h1");
assert!(build.success);
assert_eq!(build.exit_code, Some(0));
assert_eq!(build.worker, Some("w1".to_string()));
info!("TEST PASS: test_mock_historical_build_success");
}
#[test]
fn test_mock_historical_build_failure() {
init_test_logging();
info!("TEST START: test_mock_historical_build_failure");
let build = mock_historical_build("h1", "cargo test", Some("w1"), false);
assert!(!build.success);
assert_eq!(build.exit_code, Some(1));
info!("TEST PASS: test_mock_historical_build_failure");
}
#[test]
fn test_mock_local_build() {
init_test_logging();
info!("TEST START: test_mock_local_build");
let build = mock_local_build("h1", "cargo check", true);
assert!(build.worker.is_none());
info!("TEST PASS: test_mock_local_build");
}
#[test]
fn test_mock_historical_build_with_duration() {
init_test_logging();
info!("TEST START: test_mock_historical_build_with_duration");
let build = mock_historical_build_with_duration("h1", "cmd", 5000, true);
assert_eq!(build.duration_ms, 5000);
info!("TEST PASS: test_mock_historical_build_with_duration");
}
#[test]
fn test_mock_daemon_running() {
init_test_logging();
info!("TEST START: test_mock_daemon_running");
let daemon = mock_daemon_running();
assert_eq!(daemon.status, Status::Running);
assert!(!daemon.version.is_empty());
assert!(daemon.uptime > Duration::ZERO);
info!("TEST PASS: test_mock_daemon_running");
}
#[test]
fn test_mock_daemon_stopped() {
init_test_logging();
info!("TEST START: test_mock_daemon_stopped");
let daemon = mock_daemon_stopped();
assert_eq!(daemon.status, Status::Stopped);
assert_eq!(daemon.uptime, Duration::ZERO);
info!("TEST PASS: test_mock_daemon_stopped");
}
#[test]
fn test_mock_daemon_error() {
init_test_logging();
info!("TEST START: test_mock_daemon_error");
let daemon = mock_daemon_error();
assert_eq!(daemon.status, Status::Error);
info!("TEST PASS: test_mock_daemon_error");
}
#[test]
fn test_mock_log_view() {
init_test_logging();
info!("TEST START: test_mock_log_view");
let log_view = mock_log_view("b1", 50);
assert_eq!(log_view.build_id, "b1");
assert_eq!(log_view.lines.len(), 50);
assert!(log_view.auto_scroll);
info!("TEST PASS: test_mock_log_view");
}
#[test]
fn test_mock_log_view_empty() {
init_test_logging();
info!("TEST START: test_mock_log_view_empty");
let log_view = mock_log_view_empty("b1");
assert!(log_view.lines.is_empty());
info!("TEST PASS: test_mock_log_view_empty");
}
#[test]
fn test_mock_log_view_scrolled() {
init_test_logging();
info!("TEST START: test_mock_log_view_scrolled");
let log_view = mock_log_view_scrolled("b1", 100, 25);
assert_eq!(log_view.scroll_offset, 25);
assert!(!log_view.auto_scroll);
info!("TEST PASS: test_mock_log_view_scrolled");
}
#[test]
fn test_mock_filter_with_query() {
init_test_logging();
info!("TEST START: test_mock_filter_with_query");
let filter = mock_filter_with_query("cargo");
assert_eq!(filter.query, "cargo");
assert!(filter.worker_filter.is_none());
info!("TEST PASS: test_mock_filter_with_query");
}
#[test]
fn test_mock_filter_with_worker() {
init_test_logging();
info!("TEST START: test_mock_filter_with_worker");
let filter = mock_filter_with_worker("worker-1");
assert_eq!(filter.worker_filter, Some("worker-1".to_string()));
info!("TEST PASS: test_mock_filter_with_worker");
}
#[test]
fn test_mock_filter_success_only() {
init_test_logging();
info!("TEST START: test_mock_filter_success_only");
let filter = mock_filter_success_only();
assert!(filter.success_only);
assert!(!filter.failed_only);
info!("TEST PASS: test_mock_filter_success_only");
}
#[test]
fn test_mock_filter_failed_only() {
init_test_logging();
info!("TEST START: test_mock_filter_failed_only");
let filter = mock_filter_failed_only();
assert!(!filter.success_only);
assert!(filter.failed_only);
info!("TEST PASS: test_mock_filter_failed_only");
}
#[test]
fn test_mock_state_empty() {
init_test_logging();
info!("TEST START: test_mock_state_empty");
let state = mock_state();
assert!(state.workers.is_empty());
assert!(state.active_builds.is_empty());
assert!(state.build_history.is_empty());
info!("TEST PASS: test_mock_state_empty");
}
#[test]
fn test_mock_state_with_workers() {
init_test_logging();
info!("TEST START: test_mock_state_with_workers");
let state = mock_state_with_workers(5);
assert_eq!(state.workers.len(), 5);
assert_eq!(state.daemon.status, Status::Running);
for (i, w) in state.workers.iter().enumerate() {
assert_eq!(w.id, format!("worker-{}", i + 1));
}
info!("TEST PASS: test_mock_state_with_workers");
}
#[test]
fn test_mock_state_with_builds() {
init_test_logging();
info!("TEST START: test_mock_state_with_builds");
let state = mock_state_with_builds(2, 3);
assert_eq!(state.workers.len(), 2);
assert_eq!(state.active_builds.len(), 3);
info!("TEST PASS: test_mock_state_with_builds");
}
#[test]
fn test_mock_state_with_history() {
init_test_logging();
info!("TEST START: test_mock_state_with_history");
let state = mock_state_with_history(10);
assert_eq!(state.build_history.len(), 10);
info!("TEST PASS: test_mock_state_with_history");
}
#[test]
fn test_mock_state_complete() {
init_test_logging();
info!("TEST START: test_mock_state_complete");
let state = mock_state_complete();
assert!(!state.workers.is_empty());
assert!(!state.active_builds.is_empty());
assert!(!state.build_history.is_empty());
assert_eq!(state.daemon.status, Status::Running);
info!("TEST PASS: test_mock_state_complete");
}
#[test]
fn test_mock_state_with_error() {
init_test_logging();
info!("TEST START: test_mock_state_with_error");
let state = mock_state_with_error("Connection refused");
assert_eq!(state.error, Some("Connection refused".to_string()));
assert_eq!(state.daemon.status, Status::Stopped);
info!("TEST PASS: test_mock_state_with_error");
}
#[test]
fn test_mock_state_with_help() {
init_test_logging();
info!("TEST START: test_mock_state_with_help");
let state = mock_state_with_help();
assert!(state.show_help);
info!("TEST PASS: test_mock_state_with_help");
}
#[test]
fn test_mock_state_filter_mode() {
init_test_logging();
info!("TEST START: test_mock_state_filter_mode");
let state = mock_state_filter_mode("test");
assert!(state.filter_mode);
assert_eq!(state.filter.query, "test");
info!("TEST PASS: test_mock_state_filter_mode");
}
#[test]
fn test_mock_state_with_logs() {
init_test_logging();
info!("TEST START: test_mock_state_with_logs");
let state = mock_state_with_logs(50);
assert!(state.log_view.is_some());
assert_eq!(state.log_view.as_ref().unwrap().lines.len(), 50);
assert_eq!(state.selected_panel, Panel::Logs);
info!("TEST PASS: test_mock_state_with_logs");
}
#[test]
fn test_mock_state_with_panel() {
init_test_logging();
info!("TEST START: test_mock_state_with_panel");
let state = mock_state_with_panel(Panel::BuildHistory);
assert_eq!(state.selected_panel, Panel::BuildHistory);
assert_eq!(state.selected_index, 0);
info!("TEST PASS: test_mock_state_with_panel");
}
#[test]
fn test_mock_state_accessible() {
init_test_logging();
info!("TEST START: test_mock_state_accessible");
let state = mock_state_accessible(true, ColorBlindMode::Deuteranopia);
assert!(state.high_contrast);
assert_eq!(state.color_blind, ColorBlindMode::Deuteranopia);
info!("TEST PASS: test_mock_state_accessible");
}
}