use std::process::Stdio;
use xchecker::runner::{BufferConfig, CommandSpec, Runner, WslOptions};
use xchecker::types::RunnerMode;
#[tokio::test]
async fn test_large_stdout_stream_truncation() {
let large_output_size = 3 * 1024 * 1024; let test_script = format!(
r"
import sys
# Output 3 MiB of data
for i in range({large_output_size}):
sys.stdout.write('x')
sys.stdout.flush()
"
);
let temp_dir = tempfile::tempdir().unwrap();
let script_path = temp_dir.path().join("test_large_stdout.py");
std::fs::write(&script_path, test_script).unwrap();
let _runner = Runner::new(RunnerMode::Native, WslOptions::default());
let _args = [script_path.to_string_lossy().to_string()];
let mut cmd = CommandSpec::new("python")
.arg("--version")
.to_tokio_command();
let python_check = cmd
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.await;
if python_check.is_err() || !python_check.unwrap().success() {
eprintln!("Skipping test: Python not available");
return;
}
use xchecker::ring_buffer::RingBuffer;
let mut buffer = RingBuffer::new(2 * 1024 * 1024); let large_data = vec![b'x'; 3 * 1024 * 1024];
buffer.write(&large_data);
assert!(buffer.was_truncated());
assert_eq!(buffer.len(), 2 * 1024 * 1024);
assert_eq!(buffer.total_bytes_written(), 3 * 1024 * 1024);
let result = buffer.to_string();
assert_eq!(result.len(), 2 * 1024 * 1024);
assert!(result.chars().all(|c| c == 'x'));
}
#[tokio::test]
async fn test_large_stderr_stream_truncation() {
use xchecker::ring_buffer::RingBuffer;
let mut buffer = RingBuffer::new(256 * 1024); let large_data = vec![b'e'; 512 * 1024];
buffer.write(&large_data);
assert!(buffer.was_truncated());
assert_eq!(buffer.len(), 256 * 1024);
assert_eq!(buffer.total_bytes_written(), 512 * 1024);
let result = buffer.to_string();
assert_eq!(result.len(), 256 * 1024);
assert!(result.chars().all(|c| c == 'e'));
}
#[test]
fn test_stderr_receipt_truncation() {
use xchecker::runner::{ClaudeResponse, NdjsonResult};
let large_stderr = "ERROR: ".to_string() + &"x".repeat(3000);
let response = ClaudeResponse {
stdout: String::new(),
stderr: large_stderr.clone(),
exit_code: 1,
runner_used: RunnerMode::Native,
runner_distro: None,
timed_out: false,
ndjson_result: NdjsonResult::NoValidJson {
tail_excerpt: String::new(),
},
stdout_truncated: false,
stderr_truncated: true,
stdout_total_bytes: 0,
stderr_total_bytes: large_stderr.len(),
};
let stderr_receipt = response.stderr_for_receipt(2048);
assert_eq!(stderr_receipt.len(), 2048);
assert!(stderr_receipt.ends_with("xxx"));
}
#[test]
fn test_custom_buffer_config() {
let buffer_config = BufferConfig {
stdout_cap_bytes: 1024,
stderr_cap_bytes: 512,
stderr_receipt_cap_bytes: 256,
};
let runner =
Runner::with_buffer_config(RunnerMode::Native, WslOptions::default(), buffer_config);
assert_eq!(runner.buffer_config.stdout_cap_bytes, 1024);
assert_eq!(runner.buffer_config.stderr_cap_bytes, 512);
assert_eq!(runner.buffer_config.stderr_receipt_cap_bytes, 256);
}
#[test]
fn test_incremental_buffer_writes() {
use xchecker::ring_buffer::RingBuffer;
let mut buffer = RingBuffer::new(100);
buffer.write(b"chunk1");
buffer.write(b"chunk2");
buffer.write(b"chunk3");
assert_eq!(buffer.to_string(), "chunk1chunk2chunk3");
assert_eq!(buffer.len(), 18);
assert!(!buffer.was_truncated());
buffer.write(&[b'x'; 100]);
assert!(buffer.was_truncated());
assert_eq!(buffer.len(), 100);
assert_eq!(buffer.total_bytes_written(), 118);
}
#[test]
fn test_empty_buffer() {
use xchecker::ring_buffer::RingBuffer;
let buffer = RingBuffer::new(1024);
assert!(buffer.is_empty());
assert_eq!(buffer.len(), 0);
assert_eq!(buffer.to_string(), "");
assert!(!buffer.was_truncated());
assert_eq!(buffer.total_bytes_written(), 0);
}
#[test]
fn test_buffer_exact_capacity() {
use xchecker::ring_buffer::RingBuffer;
let mut buffer = RingBuffer::new(10);
buffer.write(b"1234567890");
assert_eq!(buffer.len(), 10);
assert_eq!(buffer.to_string(), "1234567890");
assert!(!buffer.was_truncated());
buffer.write(b"X");
assert_eq!(buffer.len(), 10);
assert_eq!(buffer.to_string(), "234567890X");
assert!(buffer.was_truncated());
}