use crate::corpus::runner_helpers::{extract_test_names, format_file_patterns, parse_lcov_file_coverage};
use std::collections::HashSet;
fn test_CORPUS_RUN_018_classify_error_type() {
let (cat, conf) = classify_error("type mismatch in assignment");
assert_eq!(cat.as_deref(), Some("type_error"));
assert!(conf.is_some());
}
#[test]
fn test_CORPUS_RUN_019_classify_error_unknown() {
let (cat, conf) = classify_error("something went wrong");
assert_eq!(cat.as_deref(), Some("unknown"));
assert!(conf.is_some());
}
#[test]
fn test_CORPUS_RUN_020_mr5_subsumption_top_level() {
let runner = CorpusRunner::new(Config::default());
let entry_nested = CorpusEntry::new(
"T-MR5-1",
"nested-block",
"If/else with nested statements",
CorpusFormat::Bash,
CorpusTier::Standard,
r#"fn main() { let x = 5; if x > 3 { let msg = "big"; } else { let msg = "small"; } }"#,
"x=",
);
assert!(runner.check_mr5_subsumption(&entry_nested));
let entry_multi = CorpusEntry::new(
"T-MR5-2",
"multi-stmt",
"Multiple top-level statements",
CorpusFormat::Bash,
CorpusTier::Standard,
"fn main() { let a = 1; let b = 2; let c = 3; }",
"a=",
);
assert!(runner.check_mr5_subsumption(&entry_multi));
}
#[test]
fn test_CORPUS_RUN_021_mr6_composition() {
let runner = CorpusRunner::new(Config::default());
let entry = CorpusEntry::new(
"T-MR6-1",
"multi-let",
"Multiple let statements",
CorpusFormat::Bash,
CorpusTier::Standard,
"fn main() { let a = 1; let b = 2; }",
"a=",
);
assert!(runner.check_mr6_composition(&entry));
}
#[test]
fn test_CORPUS_RUN_022_mr7_negation() {
let runner = CorpusRunner::new(Config::default());
let entry = CorpusEntry::new(
"T-MR7-1",
"if-cond",
"If with condition",
CorpusFormat::Bash,
CorpusTier::Standard,
r#"fn main() { let x = 5; if x > 3 { let msg = "yes"; } }"#,
"x=",
);
assert!(runner.check_mr7_negation(&entry));
}
#[test]
fn test_CORPUS_RUN_023_behavioral_execution() {
let runner = CorpusRunner::new(Config::default());
assert!(runner.check_behavioral("x='42'", CorpusFormat::Bash));
assert!(runner.check_behavioral("", CorpusFormat::Bash));
assert!(runner.check_behavioral("", CorpusFormat::Dockerfile));
}
#[test]
fn test_CORPUS_RUN_060_behavioral_nonzero_exit_passes() {
let runner = CorpusRunner::new(Config::default());
assert!(
runner.check_behavioral("exit 1", CorpusFormat::Bash),
"Non-zero exit (not timeout) should still pass behavioral check"
);
}
#[test]
fn test_CORPUS_RUN_061_behavioral_timeout_fails() {
let runner = CorpusRunner::new(Config::default());
assert!(
!runner.check_behavioral("while true; do :; done", CorpusFormat::Bash),
"Infinite loop should fail behavioral check via timeout"
);
}
#[test]
fn test_CORPUS_RUN_062_behavioral_makefile_delegates() {
let runner = CorpusRunner::new(Config::default());
assert!(runner.check_behavioral("all:\n\techo ok\n", CorpusFormat::Makefile));
}
#[test]
fn test_CORPUS_RUN_024_shellcheck_integration() {
let runner = CorpusRunner::new(Config::default());
let valid = runner.check_shellcheck("#!/bin/sh\nx='hello'\necho \"$x\"");
if let Some(result) = valid {
assert!(result, "Valid POSIX script should pass shellcheck");
}
}
#[test]
fn test_CORPUS_RUN_025_makefile_dry_run() {
let runner = CorpusRunner::new(Config::default());
assert!(runner.check_makefile_dry_run("all:\n\t@echo hello\n"));
assert!(runner.check_behavioral("all:\n\t@echo hello\n", CorpusFormat::Makefile));
}
#[test]
fn test_CORPUS_RUN_026_cross_shell_execution() {
let runner = CorpusRunner::new(Config::default());
assert!(runner.check_shell_execution("x='hello'"));
assert!(runner.check_shell_execution(""));
}
#[test]
fn test_CORPUS_RUN_027_convergence_log_roundtrip() {
let tmp = std::env::temp_dir().join("bashrs_test_convergence.jsonl");
let _ = std::fs::remove_file(&tmp);
let entry1 = ConvergenceEntry {
iteration: 1,
date: "2026-02-07".to_string(),
total: 100,
passed: 95,
failed: 5,
rate: 0.95,
delta: 0.0,
notes: "first".to_string(),
..Default::default()
};
let entry2 = ConvergenceEntry {
iteration: 2,
date: "2026-02-07".to_string(),
total: 100,
passed: 98,
failed: 2,
rate: 0.98,
delta: 0.03,
notes: "second".to_string(),
..Default::default()
};
CorpusRunner::append_convergence_log(&entry1, &tmp).unwrap();
CorpusRunner::append_convergence_log(&entry2, &tmp).unwrap();
let loaded = CorpusRunner::load_convergence_log(&tmp).unwrap();
assert_eq!(loaded.len(), 2);
assert_eq!(loaded[0].iteration, 1);
assert_eq!(loaded[1].iteration, 2);
assert!((loaded[0].rate - 0.95).abs() < f64::EPSILON);
assert_eq!(loaded[1].notes, "second");
let _ = std::fs::remove_file(&tmp);
}
#[test]
fn test_CORPUS_RUN_028_convergence_log_missing_file() {
let nonexistent = std::path::Path::new("/tmp/bashrs_nonexistent_convergence_xyzzy.jsonl");
let loaded = CorpusRunner::load_convergence_log(nonexistent).unwrap();
assert!(loaded.is_empty());
}
#[test]
fn test_CORPUS_RUN_029_extract_test_names() {
let mut names = HashSet::new();
let source = r#"
#[test]
fn test_CORPUS_001_registry_loads() {
// ...
}
#[test]
fn test_CORPUS_RUN_014_detect_test_exists() {
// ...
}
fn not_a_test() {}
"#;
extract_test_names(source, &mut names);
assert!(names.contains("test_CORPUS_001_registry_loads"));
assert!(names.contains("test_CORPUS_RUN_014_detect_test_exists"));
assert!(!names.contains("not_a_test"));
}
#[test]
fn test_CORPUS_RUN_015_schema_hard_gate() {
let result = CorpusResult {
id: "T-015".to_string(),
transpiled: true,
output_contains: true,
output_exact: true,
output_behavioral: true,
schema_valid: false,
has_test: true,
coverage_ratio: 1.0,
lint_clean: true,
deterministic: true,
metamorphic_consistent: true,
cross_shell_agree: true,
expected_output: None,
actual_output: Some("invalid output".to_string()),
error: None,
error_category: None,
error_confidence: None,
decision_trace: None,
};
assert!(
result.score().abs() < f64::EPSILON,
"Schema-invalid entry should score 0, got {}",
result.score()
);
}
#[test]
fn test_CORPUS_RUN_030_parse_lcov_basic() {
let lcov = r#"SF:rash/src/emitter/posix.rs
DA:1,5
DA:2,3
DA:3,0
DA:4,10
end_of_record
SF:rash/src/emitter/makefile.rs
DA:1,1
DA:2,0
DA:3,0
end_of_record
"#;
let results = parse_lcov_file_coverage(lcov);
assert_eq!(results.len(), 2);
assert_eq!(results[0].0, "rash/src/emitter/posix.rs");
assert_eq!(results[0].1, (4, 3));
assert_eq!(results[1].0, "rash/src/emitter/makefile.rs");
assert_eq!(results[1].1, (3, 1));
}
#[test]
fn test_CORPUS_RUN_031_parse_lcov_empty() {
let results = parse_lcov_file_coverage("");
assert!(results.is_empty());
}
#[test]
fn test_CORPUS_RUN_032_coverage_ratio_scoring() {
let result = CorpusResult {
id: "T-032".to_string(),
transpiled: true,
output_contains: true,
output_exact: true,
output_behavioral: true,
schema_valid: true,
has_test: true,
coverage_ratio: 0.8,
lint_clean: true,
deterministic: true,
metamorphic_consistent: true,
cross_shell_agree: true,
expected_output: None,
actual_output: Some("output".to_string()),
error: None,
error_category: None,
error_confidence: None,
decision_trace: None,
};
let score = result.score();
assert!(
(score - 97.0).abs() < f64::EPSILON,
"Expected 97.0, got {score}"
);
}
#[test]
fn test_CORPUS_RUN_033_coverage_ratio_zero() {
let result = CorpusResult {
id: "T-033".to_string(),
transpiled: true,
output_contains: true,
output_exact: true,
output_behavioral: true,
schema_valid: true,
has_test: false,
coverage_ratio: 0.0,
lint_clean: true,
deterministic: true,
metamorphic_consistent: true,
cross_shell_agree: true,
expected_output: None,
actual_output: Some("output".to_string()),
error: None,
error_category: None,
error_confidence: None,
decision_trace: None,
};
let score = result.score();
assert!(
(score - 85.0).abs() < f64::EPSILON,
"Expected 85.0, got {score}"
);
}
#[test]
fn test_CORPUS_RUN_034_format_file_patterns() {
let bash_patterns = format_file_patterns(CorpusFormat::Bash);
assert!(!bash_patterns.is_empty());
assert!(bash_patterns.iter().any(|p| p.contains("posix")));
let make_patterns = format_file_patterns(CorpusFormat::Makefile);
assert!(make_patterns.iter().any(|p| p.contains("makefile")));
let docker_patterns = format_file_patterns(CorpusFormat::Dockerfile);
assert!(docker_patterns.iter().any(|p| p.contains("dockerfile")));
}
#[test]
include!("runner_tests_tests_CORPUS_2.rs");