use batless::{process_file, BatlessConfig};
use proptest::prelude::*;
use std::io::Write;
use tempfile::NamedTempFile;
proptest! {
#![proptest_config(ProptestConfig::with_cases(100))]
#[test]
fn test_process_file_never_panics(
content in ".*",
max_lines in 1usize..1000,
max_bytes in proptest::option::of(1usize..10000)
) {
let mut file = NamedTempFile::new().expect("Failed to create test file");
file.write_all(content.as_bytes()).expect("Failed to write test content");
let config = BatlessConfig {
max_lines,
max_bytes,
..Default::default()
};
if let Some(path) = file.path().to_str() {
let _result = process_file(path, &config);
}
}
#[test]
fn test_max_lines_respected(
lines in prop::collection::vec(".*", 1..50),
max_lines in 1usize..25
) {
let content = lines.join("\n");
let mut file = NamedTempFile::new().expect("Failed to create test file");
file.write_all(content.as_bytes()).expect("Failed to write test content");
let config = BatlessConfig {
max_lines,
..Default::default()
};
let file_path = file.path().to_str().expect("Failed to convert path");
if let Ok(result) = process_file(file_path, &config) {
prop_assert!(result.lines.len() <= max_lines);
prop_assert!(result.lines.len() <= max_lines);
}
}
#[test]
fn test_max_bytes_respected(
content in ".*",
max_bytes in 1usize..1000
) {
let mut file = NamedTempFile::new().expect("Failed to create test file");
file.write_all(content.as_bytes()).expect("Failed to write test content");
let config = BatlessConfig {
max_bytes: Some(max_bytes),
max_lines: 10000, ..Default::default()
};
let file_path = file.path().to_str().expect("Failed to convert path");
if let Ok(result) = process_file(file_path, &config) {
let mut processed_bytes = 0;
for line in &result.lines {
processed_bytes += line.len() + 1; }
prop_assert!(processed_bytes <= max_bytes + 1);
}
}
#[test]
fn test_summary_mode_stability(
rust_code in r"(fn |struct |impl |use |pub )[a-zA-Z0-9_\s\{\}\(\);]*",
) {
let mut file = NamedTempFile::new().expect("Failed to create test file");
file.write_all(rust_code.as_bytes()).expect("Failed to write test content");
let config = BatlessConfig {
summary_mode: true,
..Default::default()
};
let file_path = file.path().to_str().expect("Failed to convert path");
if let Ok(result) = process_file(file_path, &config) {
if let Some(summary_lines) = &result.summary_lines {
prop_assert!(summary_lines.len() <= result.total_lines);
let summary_text: Vec<String> =
summary_lines.iter().map(|s| s.line.clone()).collect();
prop_assert_eq!(result.lines, summary_text);
}
}
}
#[test]
fn test_encoding_detection_stability(
content in prop::collection::vec(any::<u8>(), 0..1000)
) {
let mut file = NamedTempFile::new().expect("Failed to create test file");
file.write_all(&content).expect("Failed to write test content");
let config = BatlessConfig::default();
let file_path = file.path().to_str().expect("Failed to convert path");
let _result = process_file(file_path, &config);
}
#[test]
fn test_json_mode_output_is_deterministic(content in ".*") {
let mut file = NamedTempFile::new().expect("Failed to create test file");
file.write_all(content.as_bytes()).expect("Failed to write test content");
let config = BatlessConfig::default();
let file_path = file.path().to_str().expect("Failed to convert path");
let r1 = process_file(file_path, &config);
let r2 = process_file(file_path, &config);
match (r1, r2) {
(Ok(a), Ok(b)) => {
prop_assert_eq!(a.lines, b.lines, "JSON mode output should be deterministic");
prop_assert_eq!(a.total_lines, b.total_lines);
}
(Err(_), Err(_)) => {} _ => prop_assert!(false, "results should agree on success/failure"),
}
}
}