bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts

use super::*;

#[test]
fn test_PROGRESS_001_step_state_symbols() {
    assert_eq!(StepState::Pending.symbol(), "");
    assert_eq!(
        StepState::Running {
            progress: 50,
            message: String::new(),
            started_at: Instant::now()
        }
        .symbol(),
        ""
    );
    assert_eq!(
        StepState::Completed {
            duration: Duration::ZERO
        }
        .symbol(),
        ""
    );
    assert_eq!(
        StepState::Failed {
            error: String::new(),
            duration: Duration::ZERO
        }
        .symbol(),
        ""
    );
    assert_eq!(
        StepState::Skipped {
            reason: String::new()
        }
        .symbol(),
        ""
    );
}

#[test]
fn test_PROGRESS_002_step_state_terminal() {
    assert!(!StepState::Pending.is_terminal());
    assert!(!StepState::Running {
        progress: 50,
        message: String::new(),
        started_at: Instant::now()
    }
    .is_terminal());
    assert!(StepState::Completed {
        duration: Duration::ZERO
    }
    .is_terminal());
    assert!(StepState::Failed {
        error: String::new(),
        duration: Duration::ZERO
    }
    .is_terminal());
    assert!(StepState::Skipped {
        reason: String::new()
    }
    .is_terminal());
}

#[test]
fn test_PROGRESS_003_progress_tracker_add_step() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.add_step("step-2", "Second Step");

    assert_eq!(progress.total_steps(), 2);
    assert!(progress.get_step("step-1").is_some());
    assert!(progress.get_step("step-2").is_some());
    assert!(progress.get_step("step-3").is_none());
}

#[test]
fn test_PROGRESS_004_progress_tracker_start_step() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.start_step("step-1", "Starting...");

    let step = progress.get_step("step-1").unwrap();
    assert!(matches!(step.state, StepState::Running { .. }));
}

#[test]
fn test_PROGRESS_005_progress_tracker_update_step() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.start_step("step-1", "Starting...");
    progress.update_step("step-1", 50, "Halfway");

    let step = progress.get_step("step-1").unwrap();
    if let StepState::Running {
        progress, message, ..
    } = &step.state
    {
        assert_eq!(*progress, 50);
        assert_eq!(message, "Halfway");
    } else {
        panic!("Expected Running state");
    }
}

#[test]
fn test_PROGRESS_006_progress_tracker_complete_step() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.start_step("step-1", "Starting...");
    progress.complete_step("step-1");

    let step = progress.get_step("step-1").unwrap();
    assert!(matches!(step.state, StepState::Completed { .. }));
    assert_eq!(progress.completed_count(), 1);
}

#[test]
fn test_PROGRESS_007_progress_tracker_fail_step() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.start_step("step-1", "Starting...");
    progress.fail_step("step-1", "Something went wrong");

    let step = progress.get_step("step-1").unwrap();
    if let StepState::Failed { error, .. } = &step.state {
        assert_eq!(error, "Something went wrong");
    } else {
        panic!("Expected Failed state");
    }
    assert_eq!(progress.failed_count(), 1);
}

#[test]
fn test_PROGRESS_008_progress_tracker_skip_step() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.skip_step("step-1", "Not needed");

    let step = progress.get_step("step-1").unwrap();
    if let StepState::Skipped { reason } = &step.state {
        assert_eq!(reason, "Not needed");
    } else {
        panic!("Expected Skipped state");
    }
    assert_eq!(progress.skipped_count(), 1);
}

#[test]
fn test_PROGRESS_009_progress_tracker_is_complete() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.add_step("step-2", "Second Step");

    assert!(!progress.is_complete());

    progress.start_step("step-1", "Starting...");
    progress.complete_step("step-1");
    assert!(!progress.is_complete());

    progress.skip_step("step-2", "Skipped");
    assert!(progress.is_complete());
}

#[test]
fn test_PROGRESS_010_progress_tracker_has_failures() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");

    assert!(!progress.has_failures());

    progress.start_step("step-1", "Starting...");
    progress.fail_step("step-1", "Error");

    assert!(progress.has_failures());
}

#[test]
fn test_PROGRESS_011_execution_mode_labels() {
    assert_eq!(ExecutionMode::Normal.label(), "NORMAL");
    assert_eq!(ExecutionMode::DryRun.label(), "DRY-RUN");
    assert_eq!(ExecutionMode::Hermetic.label(), "HERMETIC");
    assert_eq!(ExecutionMode::Test.label(), "TEST");
}

#[test]
fn test_PROGRESS_012_terminal_renderer_header() {
    let progress = InstallerProgress::new("docker-ce", "1.0.0");
    let renderer = TerminalRenderer::with_width(40);
    let header = renderer.render_header(&progress);

    assert!(header.contains("docker-ce"));
    assert!(header.contains("v1.0.0"));
}

#[test]
fn test_PROGRESS_013_terminal_renderer_step() {
    let step = StepInfo {
        id: "install".to_string(),
        name: "Install Package".to_string(),
        state: StepState::Completed {
            duration: Duration::from_secs(5),
        },
        index: 1,
    };

    let renderer = TerminalRenderer::new();
    let output = renderer.render_step(&step, 3);

    assert!(output.contains("Install Package"));
    assert!(output.contains(""));
    assert!(output.contains("100%"));
}

#[test]
fn test_PROGRESS_014_json_renderer() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First Step");
    progress.start_step("step-1", "Running");
    progress.complete_step("step-1");

    let renderer = JsonRenderer::new();
    let output = renderer.render(&progress);

    assert!(output.contains("\"steps\""));
    assert!(output.contains("\"id\": \"step-1\""));
    assert!(output.contains("\"status\": \"completed\""));
}

#[test]
fn test_PROGRESS_015_generate_summary() {
    let mut progress = InstallerProgress::new("test", "1.0.0");
    progress.add_step("step-1", "First");
    progress.add_step("step-2", "Second");
    progress.start_step("step-1", "Running");
    progress.complete_step("step-1");
    progress.skip_step("step-2", "Not needed");

    let summary = generate_summary(&progress);

    assert_eq!(summary.total_steps, 2);
    assert_eq!(summary.completed, 1);
    assert_eq!(summary.skipped, 1);
    assert!(summary.success);
}

#[test]
fn test_PROGRESS_016_summary_format() {
    let summary = InstallationSummary {
        name: "test".to_string(),
        version: "1.0.0".to_string(),
        total_steps: 3,
        completed: 2,
        failed: 1,
        skipped: 0,
        total_duration: Duration::from_secs(65),
        success: false,
        step_results: vec![StepResult {
            id: "failed-step".to_string(),
            name: "Failed Step".to_string(),
            status: "failed".to_string(),
            duration: Some(Duration::from_secs(5)),
            message: Some("Error occurred".to_string()),
        }],
    };

    let output = summary.format();
    assert!(output.contains("FAILED"));
    assert!(output.contains("1m 05s"));
    assert!(output.contains("failed-step"));
}

#[test]
fn test_PROGRESS_017_summary_to_json() {
    let summary = InstallationSummary {
        name: "test".to_string(),
        version: "1.0.0".to_string(),
        total_steps: 2,
        completed: 2,
        failed: 0,
        skipped: 0,
        total_duration: Duration::from_secs(10),
        success: true,
        step_results: vec![],
    };

    let json = summary.to_json();
    assert!(json.contains("\"success\": true"));
    assert!(json.contains("\"completed\": 2"));
}

#[test]
fn test_PROGRESS_018_truncate() {
    assert_eq!(truncate("short", 10), "short");
    assert_eq!(truncate("this is a long string", 10), "this is...");
}

#[test]
fn test_PROGRESS_019_escape_json() {
    assert_eq!(escape_json("hello"), "hello");
    assert_eq!(escape_json("line1\nline2"), "line1\\nline2");
    assert_eq!(escape_json("say \"hi\""), "say \\\"hi\\\"");
}

#[test]
fn test_PROGRESS_020_progress_bar() {
    let renderer = TerminalRenderer::with_width(80);

    let bar_0 = renderer.progress_bar(0, 10);
    assert_eq!(bar_0.chars().count(), 10);

    let bar_50 = renderer.progress_bar(50, 10);
    assert_eq!(bar_50.chars().count(), 10);

    let bar_100 = renderer.progress_bar(100, 10);
    assert_eq!(bar_100.chars().count(), 10);
}