#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use super::*;
use crate::corpus::registry::{CorpusEntry, CorpusFormat, CorpusRegistry, CorpusTier, Grade};
use crate::corpus::runner::{CorpusResult, CorpusScore, FormatScore};
fn make_entry(id: &str, format: CorpusFormat) -> CorpusEntry {
CorpusEntry {
id: id.to_string(),
name: format!("test-{id}"),
description: "Test entry".to_string(),
format,
tier: CorpusTier::Trivial,
input: "fn main() {}".to_string(),
expected_output: "#!/bin/sh\necho ok\n".to_string(),
shellcheck: true,
deterministic: true,
idempotent: true,
}
}
fn make_result(id: &str, transpiled: bool) -> CorpusResult {
CorpusResult {
id: id.to_string(),
transpiled,
output_contains: transpiled,
output_exact: transpiled,
output_behavioral: transpiled,
has_test: true,
coverage_ratio: 0.95,
schema_valid: true,
lint_clean: transpiled,
deterministic: transpiled,
metamorphic_consistent: transpiled,
cross_shell_agree: transpiled,
expected_output: None,
actual_output: if transpiled {
Some("#!/bin/sh\necho ok\n".to_string())
} else {
None
},
error: if transpiled {
None
} else {
Some("test error".to_string())
},
error_category: None,
error_confidence: None,
decision_trace: None,
}
}
fn make_score(
total: usize,
passed: usize,
failed: usize,
rate: f64,
score_val: f64,
grade: Grade,
format_count: usize,
) -> CorpusScore {
let format_scores: Vec<FormatScore> = (0..format_count)
.map(|i| {
let fmt = match i {
0 => CorpusFormat::Bash,
1 => CorpusFormat::Makefile,
_ => CorpusFormat::Dockerfile,
};
FormatScore {
format: fmt,
total: total / format_count.max(1),
passed: passed / format_count.max(1),
rate,
score: score_val,
grade,
}
})
.collect();
CorpusScore {
total,
passed,
failed,
rate,
score: score_val,
grade,
format_scores,
results: vec![],
}
}
#[test]
fn test_grade_a_plus_boundary() {
assert_eq!(score_to_grade(97.0), "A+");
assert_eq!(score_to_grade(100.0), "A+");
assert_eq!(score_to_grade(98.5), "A+");
}
#[test]
fn test_grade_a_boundary() {
assert_eq!(score_to_grade(93.0), "A");
assert_eq!(score_to_grade(96.0), "A");
assert_eq!(score_to_grade(96.9), "A");
}
#[test]
fn test_grade_a_minus_boundary() {
assert_eq!(score_to_grade(90.0), "A-");
assert_eq!(score_to_grade(92.0), "A-");
assert_eq!(score_to_grade(92.9), "A-");
}
#[test]
fn test_grade_b_plus_boundary() {
assert_eq!(score_to_grade(87.0), "B+");
assert_eq!(score_to_grade(89.0), "B+");
assert_eq!(score_to_grade(89.9), "B+");
}
#[test]
fn test_grade_b_boundary() {
assert_eq!(score_to_grade(83.0), "B");
assert_eq!(score_to_grade(86.0), "B");
}
#[test]
fn test_grade_b_minus_boundary() {
assert_eq!(score_to_grade(80.0), "B-");
assert_eq!(score_to_grade(82.0), "B-");
}
#[test]
fn test_grade_c_plus_boundary() {
assert_eq!(score_to_grade(77.0), "C+");
assert_eq!(score_to_grade(79.0), "C+");
}
#[test]
fn test_grade_c_boundary() {
assert_eq!(score_to_grade(73.0), "C");
assert_eq!(score_to_grade(76.0), "C");
}
#[test]
fn test_grade_c_minus_boundary() {
assert_eq!(score_to_grade(70.0), "C-");
assert_eq!(score_to_grade(72.0), "C-");
}
#[test]
fn test_grade_d_boundary() {
assert_eq!(score_to_grade(60.0), "D");
assert_eq!(score_to_grade(69.0), "D");
}
#[test]
fn test_grade_f_below_60() {
assert_eq!(score_to_grade(59.0), "F");
assert_eq!(score_to_grade(0.0), "F");
assert_eq!(score_to_grade(30.0), "F");
}
#[test]
fn test_export_jsonl_empty() {
let output = export_jsonl(&[]);
assert_eq!(output, "");
}
#[test]
fn test_export_json_empty() {
let output = export_json(&[]);
assert_eq!(output, "[]");
}
#[test]
fn test_export_csv_empty() {
let output = export_csv(&[]);
assert!(output.starts_with("id,name,tier,format"));
assert_eq!(output.lines().count(), 1);
}
#[test]
fn test_export_jsonl_multiple_rows() {
let rows = vec![
build_row(
&make_entry("B-001", CorpusFormat::Bash),
Some(&make_result("B-001", true)),
"1.0.0",
"abc",
"2026-01-01",
),
build_row(
&make_entry("M-001", CorpusFormat::Makefile),
Some(&make_result("M-001", false)),
"1.0.0",
"abc",
"2026-01-01",
),
];
let output = export_jsonl(&rows);
assert_eq!(output.lines().count(), 2);
assert!(output.lines().nth(0).unwrap().contains("B-001"));
assert!(output.lines().nth(1).unwrap().contains("M-001"));
}
#[test]
fn test_export_json_pretty_printed() {
let row = build_row(
&make_entry("D-001", CorpusFormat::Dockerfile),
None,
"1.0.0",
"abc",
"2026-01-01",
);
let output = export_json(&[row]);
assert!(output.contains('\n'));
assert!(output.contains(" "));
assert!(output.contains("\"format\": \"dockerfile\""));
}
#[test]
fn test_csv_escape_plain_string() {
assert_eq!(csv_escape("hello"), "hello");
}
#[test]
fn test_csv_escape_with_comma() {
assert_eq!(csv_escape("a,b"), "\"a,b\"");
}
#[test]
fn test_csv_escape_with_quotes() {
assert_eq!(csv_escape("say \"hi\""), "\"say \"\"hi\"\"\"");
}
#[test]
fn test_csv_escape_with_newline() {
assert_eq!(csv_escape("line1\nline2"), "\"line1\nline2\"");
}
#[test]
fn test_csv_escape_with_all_specials() {
let s = "a,b\"c\nd";
let escaped = csv_escape(s);
assert!(escaped.starts_with('"'));
assert!(escaped.ends_with('"'));
}
#[test]
fn test_build_row_partial_correctness() {
let mut result = make_result("B-010", true);
result.output_exact = false;
let row = build_row(
&make_entry("B-010", CorpusFormat::Bash),
Some(&result),
"1.0.0",
"abc",
"2026-01-01",
);
assert!(row.transpiled);
assert!(!row.output_correct); }
#[test]
fn test_build_row_not_deterministic() {
let mut result = make_result("B-011", true);
result.deterministic = false;
let row = build_row(
&make_entry("B-011", CorpusFormat::Bash),
Some(&result),
"1.0.0",
"abc",
"2026-01-01",
);
assert!(!row.deterministic);
}
#[test]
fn test_build_row_not_lint_clean() {
let mut result = make_result("B-012", true);
result.lint_clean = false;
let row = build_row(
&make_entry("B-012", CorpusFormat::Bash),
Some(&result),
"1.0.0",
"abc",
"2026-01-01",
);
assert!(!row.lint_clean);
}
#[test]
fn test_build_row_tier_preserved() {
let mut entry = make_entry("B-020", CorpusFormat::Bash);
entry.tier = CorpusTier::Adversarial;
let row = build_row(&entry, None, "1.0.0", "abc", "2026-01-01");
assert_eq!(row.tier, CorpusTier::Adversarial as u8);
}
#[test]
fn test_build_row_format_string() {
let entry = make_entry("M-020", CorpusFormat::Makefile);
let row = build_row(&entry, None, "1.0.0", "abc", "2026-01-01");
assert_eq!(row.format, "makefile");
}
#[test]
fn test_build_dataset_matches_entries_to_results() {
let entries = vec![
make_entry("B-001", CorpusFormat::Bash),
make_entry("B-002", CorpusFormat::Bash),
];
let registry = CorpusRegistry { entries };
let results = vec![make_result("B-001", true)];
let score = CorpusScore {
total: 2,
passed: 1,
failed: 1,
rate: 0.5,
score: 50.0,
grade: Grade::F,
format_scores: vec![],
results,
};
let rows = build_dataset(®istry, &score);
assert_eq!(rows.len(), 2);
assert!(rows[0].transpiled); assert!(!rows[1].transpiled); assert_eq!(rows[1].grade, "F");
}
#[test]
include!("dataset_tests_tests_publish.rs");