bashrs 6.66.0

Rust-to-Shell transpiler for deterministic bootstrap scripts
fn test_RUNNER_COV2_014_converged_edge_cases() {
    assert!(!CorpusRunner::is_converged(&[]));
    assert!(!CorpusRunner::is_converged(&[
        ConvergenceEntry {
            rate: 0.99,
            delta: 0.001,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.995,
            delta: 0.002,
            ..Default::default()
        },
    ]));
    // Unstable delta
    assert!(!CorpusRunner::is_converged(&[
        ConvergenceEntry {
            rate: 0.99,
            delta: 0.001,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.995,
            delta: 0.001,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.992,
            delta: 0.01,
            ..Default::default()
        },
    ]));
    // Rate below threshold
    assert!(!CorpusRunner::is_converged(&[
        ConvergenceEntry {
            rate: 0.98,
            delta: 0.0,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.98,
            delta: 0.0,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.98,
            delta: 0.0,
            ..Default::default()
        },
    ]));
    // Negative delta, all stable
    assert!(CorpusRunner::is_converged(&[
        ConvergenceEntry {
            rate: 0.995,
            delta: -0.001,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.993,
            delta: -0.002,
            ..Default::default()
        },
        ConvergenceEntry {
            rate: 0.992,
            delta: -0.001,
            ..Default::default()
        },
    ]));
}

// --- score combinations ---

#[test]
fn test_RUNNER_COV2_015_score_combinations() {
    // A=30, D=10, E=10
    let r1 = CorpusResult {
        transpiled: true,
        schema_valid: true,
        lint_clean: true,
        deterministic: true,
        ..Default::default()
    };
    assert!((r1.score() - 50.0).abs() < 0.01);
    // A=30, F=5
    let r2 = CorpusResult {
        transpiled: true,
        schema_valid: true,
        metamorphic_consistent: true,
        ..Default::default()
    };
    assert!((r2.score() - 35.0).abs() < 0.01);
    // A=30, G=5
    let r3 = CorpusResult {
        transpiled: true,
        schema_valid: true,
        cross_shell_agree: true,
        ..Default::default()
    };
    assert!((r3.score() - 35.0).abs() < 0.01);
    // All B levels: A=30, B1=10, B2=8, B3=7
    let r4 = CorpusResult {
        transpiled: true,
        schema_valid: true,
        output_contains: true,
        output_exact: true,
        output_behavioral: true,
        ..Default::default()
    };
    assert!((r4.score() - 55.0).abs() < 0.01);
    // L1 gates L2/L3: A=30, C=15, D=10, E=10, F=5, G=5 = 75
    let r5 = CorpusResult {
        transpiled: true,
        schema_valid: true,
        output_contains: false,
        output_exact: true,
        output_behavioral: true,
        coverage_ratio: 1.0,
        lint_clean: true,
        deterministic: true,
        metamorphic_consistent: true,
        cross_shell_agree: true,
        ..Default::default()
    };
    assert!((r5.score() - 75.0).abs() < 0.01);
    // V1 partial: A=40, B=25, C=7.5, D=0, E=10 = 82.5
    let r6 = CorpusResult {
        transpiled: true,
        output_contains: true,
        coverage_ratio: 0.5,
        deterministic: true,
        ..Default::default()
    };
    assert!((r6.score_v1() - 82.5).abs() < 0.01);
}

// --- Grade boundaries ---

#[test]
fn test_RUNNER_COV2_016_grade_boundaries() {
    assert_eq!(Grade::from_score(100.0), Grade::APlus);
    assert_eq!(Grade::from_score(97.0), Grade::APlus);
    assert_eq!(Grade::from_score(96.9), Grade::A);
    assert_eq!(Grade::from_score(89.9), Grade::B);
    assert_eq!(Grade::from_score(79.9), Grade::C);
    assert_eq!(Grade::from_score(69.9), Grade::D);
    assert_eq!(Grade::from_score(59.9), Grade::F);
}

// --- detect_regressions ---

#[test]
fn test_RUNNER_COV2_017_regressions() {
    let base = ConvergenceEntry {
        score: 95.0,
        passed: 900,
        bash_passed: 500,
        makefile_passed: 200,
        dockerfile_passed: 200,
        bash_score: 99.0,
        makefile_score: 100.0,
        dockerfile_score: 99.5,
        lint_passed: 890,
        ..Default::default()
    };
    // Equal: no regressions
    assert!(!base.detect_regressions(&base).has_regressions());
    // All improve: no regressions
    let better = ConvergenceEntry {
        score: 96.0,
        passed: 910,
        bash_passed: 510,
        makefile_passed: 200,
        dockerfile_passed: 200,
        bash_score: 99.5,
        makefile_score: 100.0,
        dockerfile_score: 100.0,
        lint_passed: 900,
        ..Default::default()
    };
    assert!(!better.detect_regressions(&base).has_regressions());
    // Lint-only regression
    let lint_drop = ConvergenceEntry {
        lint_passed: 880,
        ..base.clone()
    };
    let report = lint_drop.detect_regressions(&base);
    assert!(report.has_regressions());
    assert!(report
        .regressions
        .iter()
        .any(|r| r.dimension == "lint_passed"));
}

// --- CorpusScore lookups and gateway ---

#[test]
fn test_RUNNER_COV2_018_score_lookups() {
    let cs = CorpusScore {
        total: 100,
        passed: 90,
        failed: 10,
        rate: 0.9,
        score: 85.0,
        grade: Grade::B,
        format_scores: vec![FormatScore {
            format: CorpusFormat::Makefile,
            total: 30,
            passed: 28,
            rate: 28.0 / 30.0,
            score: 92.0,
            grade: Grade::A,
        }],
        results: vec![],
    };
    assert!(cs.format_score(CorpusFormat::Makefile).is_some());
    assert!(cs.format_score(CorpusFormat::Bash).is_none());
    assert!(cs.gateway_met());

    let below = CorpusScore {
        rate: 0.59,
        ..cs.clone()
    };
    assert!(!below.gateway_met());
}

// --- run_single with deterministic=false ---

#[test]
fn test_RUNNER_COV2_019_no_determinism_check() {
    let r = runner();
    let mut entry = bash_entry("T-RC2-019", "fn main() { let x = 42; }", "x=");
    entry.deterministic = false;
    let result = r.run_single(&entry);
    if result.transpiled {
        assert!(result.deterministic);
    }
}

// --- Serde roundtrips ---

#[test]
fn test_RUNNER_COV2_020_serde_roundtrips() {
    // CorpusScore
    let score = CorpusScore {
        total: 10,
        passed: 8,
        failed: 2,
        rate: 0.8,
        score: 85.0,
        grade: Grade::B,
        format_scores: vec![FormatScore {
            format: CorpusFormat::Bash,
            total: 10,
            passed: 8,
            rate: 0.8,
            score: 85.0,
            grade: Grade::B,
        }],
        results: vec![CorpusResult {
            id: "X".into(),
            transpiled: true,
            ..Default::default()
        }],
    };
    let loaded: CorpusScore =
        serde_json::from_str(&serde_json::to_string(&score).unwrap()).unwrap();
    assert_eq!(loaded.total, 10);
    assert_eq!(loaded.format_scores.len(), 1);

    // ConvergenceEntry full
    let entry = ConvergenceEntry {
        iteration: 42,
        date: "2026-02-23".into(),
        total: 1000,
        passed: 998,
        failed: 2,
        rate: 0.998,
        delta: 0.001,
        notes: "full".into(),
        bash_passed: 700,
        bash_total: 702,
        makefile_passed: 200,
        makefile_total: 200,
        dockerfile_passed: 98,
        dockerfile_total: 98,
        score: 99.5,
        grade: "A+".into(),
        bash_score: 99.3,
        makefile_score: 100.0,
        dockerfile_score: 99.8,
        lint_passed: 995,
        lint_rate: 0.995,
    };
    let le: ConvergenceEntry =
        serde_json::from_str(&serde_json::to_string(&entry).unwrap()).unwrap();
    assert_eq!(le.iteration, 42);
    assert_eq!(le.bash_passed, 700);
    assert_eq!(le.grade, "A+");
}