use lz4::bench::config::BenchConfig;
use lz4::bench::runner::{bench_c_level, bench_file_table, load_files};
use std::io::Write;
fn quiet_config() -> BenchConfig {
let mut c = BenchConfig::default();
c.set_nb_seconds(0); c.set_notification_level(0); c
}
fn make_src() -> Vec<u8> {
(0u8..128).cycle().take(64 * 1024).collect()
}
fn make_temp_file(content: &[u8]) -> (tempfile::NamedTempFile, String) {
let mut tmp = tempfile::NamedTempFile::new().expect("tmp file");
tmp.write_all(content).expect("write tmp file");
let path = tmp.path().to_str().unwrap().to_owned();
(tmp, path)
}
#[test]
fn load_files_empty_path_list_returns_no_data_error() {
let config = quiet_config();
let result = load_files(&[], 1024, &config);
assert!(result.is_err(), "empty path list must return Err");
let err = result.unwrap_err();
assert_eq!(
err.kind(),
std::io::ErrorKind::InvalidInput,
"expected InvalidInput, got {:?}",
err.kind()
);
assert!(
err.to_string().contains("no data to bench"),
"error message should mention 'no data to bench': {}",
err
);
}
#[test]
fn load_files_reads_single_file_correctly() {
let content = b"hello benchmark world!";
let (_tmp, path) = make_temp_file(content);
let config = quiet_config();
let (buf, sizes) =
load_files(&[&path], 4096, &config).expect("load_files must succeed for a valid file");
assert_eq!(&buf[..], content, "buffer content must match file content");
assert_eq!(
sizes[0],
content.len(),
"file_sizes[0] must equal file length"
);
}
#[test]
fn load_files_returns_exact_file_size_in_sizes_vec() {
let content: Vec<u8> = (0u8..=255).cycle().take(512).collect();
let (_tmp, path) = make_temp_file(&content);
let config = quiet_config();
let (_buf, sizes) = load_files(&[&path], 4096, &config).unwrap();
assert_eq!(sizes[0], 512);
}
#[test]
fn load_files_truncates_to_buffer_size() {
let content = b"abcdefghijklmnopqrstuvwxyz"; let (_tmp, path) = make_temp_file(content);
let config = quiet_config();
let (buf, sizes) =
load_files(&[&path], 10, &config).expect("truncated load should succeed (returns data)");
assert_eq!(buf.len(), 10, "buffer must be truncated to buffer_size");
assert_eq!(sizes[0], 10, "file_sizes[0] must reflect truncation");
assert_eq!(&buf[..], &content[..10]);
}
#[test]
fn load_files_skips_directory_entry() {
let content = b"real file content";
let (_tmp, file_path) = make_temp_file(content);
let config = quiet_config();
let paths: &[&str] = &["/tmp", &file_path];
let (buf, sizes) = load_files(paths, 4096, &config)
.expect("load_files should skip /tmp and read the real file");
assert_eq!(sizes[0], 0, "directory entry should have size 0");
assert_eq!(sizes[1], content.len());
assert_eq!(&buf[..], content);
}
#[test]
fn load_files_multiple_files_concatenated() {
let content_a = b"AAAA";
let content_b = b"BBBB";
let (_tmp_a, path_a) = make_temp_file(content_a);
let (_tmp_b, path_b) = make_temp_file(content_b);
let config = quiet_config();
let (buf, sizes) = load_files(&[&path_a, &path_b], 4096, &config).unwrap();
assert_eq!(sizes[0], 4);
assert_eq!(sizes[1], 4);
assert_eq!(buf.len(), 8);
assert_eq!(&buf[0..4], content_a);
assert_eq!(&buf[4..8], content_b);
}
#[test]
fn load_files_missing_file_returns_error() {
let config = quiet_config();
let result = load_files(
&["/nonexistent_file_that_does_not_exist.bin"],
4096,
&config,
);
assert!(result.is_err(), "missing file must return Err");
}
#[test]
fn load_files_buffer_exactly_file_size_succeeds() {
let content = b"exactly fits";
let (_tmp, path) = make_temp_file(content);
let config = quiet_config();
let (buf, sizes) = load_files(&[&path], content.len(), &config).unwrap();
assert_eq!(buf.len(), content.len());
assert_eq!(sizes[0], content.len());
assert_eq!(&buf[..], content);
}
#[test]
fn bench_c_level_single_level_succeeds() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "test_input", 1, 1, &config, b"", &[]);
assert!(
result.is_ok(),
"bench_c_level level 1 must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_c_level_multiple_levels_succeeds() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "multi", 1, 3, &config, b"", &[]);
assert!(
result.is_ok(),
"bench_c_level levels 1–3 must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_c_level_clamped_when_last_less_than_first() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "clamped", 5, 2, &config, b"", &[]);
assert!(
result.is_ok(),
"clamped cLevelLast must still succeed: {:?}",
result.err()
);
}
#[test]
fn bench_c_level_equal_first_and_last_succeeds() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "eq_levels", 3, 3, &config, b"", &[]);
assert!(result.is_ok(), "equal first/last level must succeed");
}
#[test]
fn bench_c_level_strips_posix_path_prefix() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "/some/path/to/file.lz4", 1, 1, &config, b"", &[]);
assert!(result.is_ok(), "POSIX path as display_name must not fail");
}
#[test]
fn bench_c_level_strips_windows_path_prefix() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "C:\\Users\\user\\file.lz4", 1, 1, &config, b"", &[]);
assert!(result.is_ok(), "Windows path as display_name must not fail");
}
#[test]
fn bench_c_level_plain_filename_no_separator() {
let src = make_src();
let config = quiet_config();
let result = bench_c_level(&src, "justfilename.bin", 1, 1, &config, b"", &[]);
assert!(
result.is_ok(),
"plain filename with no separator must not fail"
);
}
#[test]
fn bench_c_level_empty_src_succeeds() {
let config = quiet_config();
let _ = bench_c_level(&[], "empty", 1, 1, &config, b"", &[]);
}
#[test]
fn bench_c_level_with_dict() {
let src = make_src();
let dict: Vec<u8> = (0u8..255).collect();
let config = quiet_config();
let result = bench_c_level(&src, "dicttest", 1, 1, &config, &dict, &[]);
assert!(
result.is_ok(),
"bench_c_level with non-empty dict must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_c_level_display_level_1_no_additional_param() {
let src = make_src();
let mut config = BenchConfig::default();
config.set_nb_seconds(0);
config.set_notification_level(1); let result = bench_c_level(&src, "verbose1", 1, 1, &config, b"", &[]);
assert!(
result.is_ok(),
"display_level=1 path must not fail: {:?}",
result.err()
);
}
#[test]
fn bench_file_table_single_file_succeeds() {
let content: Vec<u8> = (0u8..=255).cycle().take(16 * 1024).collect();
let (_tmp, path) = make_temp_file(&content);
let config = quiet_config();
let result = bench_file_table(&[&path], 1, 1, b"", &config);
assert!(
result.is_ok(),
"bench_file_table single file must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_file_table_multiple_files_display_name_format() {
let content: Vec<u8> = (0u8..=127).cycle().take(8 * 1024).collect();
let (_tmp_a, path_a) = make_temp_file(&content);
let (_tmp_b, path_b) = make_temp_file(&content);
let config = quiet_config();
let result = bench_file_table(&[&path_a, &path_b], 1, 1, b"", &config);
assert!(
result.is_ok(),
"bench_file_table multiple files must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_file_table_missing_file_propagates_error() {
let config = quiet_config();
let result = bench_file_table(&["/nonexistent_file_xyz_abc.bin"], 1, 1, b"", &config);
assert!(
result.is_err(),
"missing file must cause bench_file_table to return Err"
);
}
#[test]
fn bench_file_table_level_range_1_to_3() {
let content: Vec<u8> = b"hello ".iter().cycle().take(32 * 1024).cloned().collect();
let (_tmp, path) = make_temp_file(&content);
let config = quiet_config();
let result = bench_file_table(&[&path], 1, 3, b"", &config);
assert!(
result.is_ok(),
"bench_file_table levels 1–3 must succeed: {:?}",
result.err()
);
}