use lz4::bench::bench_files;
use lz4::bench::config::BenchConfig;
use lz4::bench::config::LZ4_MAX_DICT_SIZE;
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_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 bench_files_empty_list_runs_synthetic_test() {
let config = quiet_config();
let result = bench_files(&[], 1, 1, None, &config);
assert!(
result.is_ok(),
"synthetic test must return Ok: {:?}",
result.err()
);
}
#[test]
fn bench_files_empty_list_multiple_levels_ok() {
let config = quiet_config();
let result = bench_files(&[], 1, 3, None, &config);
assert!(
result.is_ok(),
"synthetic multi-level must return Ok: {:?}",
result.err()
);
}
#[test]
fn bench_files_empty_list_level_last_below_first_ok() {
let config = quiet_config();
let result = bench_files(&[], 3, 1, None, &config);
assert!(result.is_ok(), "clamped level range must return Ok");
}
#[test]
fn bench_files_level_above_max_is_clamped_ok() {
let config = quiet_config();
let result = bench_files(&[], 999, 999, None, &config);
assert!(
result.is_ok(),
"over-max level must be clamped and succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_level_last_above_max_is_clamped_ok() {
let config = quiet_config();
let result = bench_files(&[], 1, 999, None, &config);
assert!(
result.is_ok(),
"over-max c_level_last must be clamped and succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_decode_only_collapses_level_range() {
let mut config = quiet_config();
config.set_decode_only(true);
let result = bench_files(&[], 1, 5, None, &config);
let _ = result; }
#[test]
fn bench_files_decode_only_with_dict_returns_err() {
let content = b"a dictionary payload";
let (_tmp, dict_path) = make_temp_file(content);
let mut config = quiet_config();
config.set_decode_only(true);
let result = bench_files(&[], 1, 1, Some(&dict_path), &config);
assert!(result.is_err(), "decode_only + dict must return Err");
let err = result.unwrap_err();
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput);
assert!(
err.to_string().contains("not compatible with dictionary"),
"error message should mention compatibility: {}",
err
);
}
#[test]
fn bench_files_missing_dict_file_returns_err() {
let config = quiet_config();
let result = bench_files(&[], 1, 1, Some("/nonexistent_dict_xyz.bin"), &config);
assert!(result.is_err(), "missing dict file must return Err");
}
#[test]
fn bench_files_empty_dict_file_returns_err() {
let (_tmp, dict_path) = make_temp_file(b"");
let config = quiet_config();
let result = bench_files(&[], 1, 1, Some(&dict_path), &config);
assert!(result.is_err(), "empty dict file must return Err");
}
#[test]
fn bench_files_dict_file_smaller_than_max_used_fully() {
let dict_content: Vec<u8> = (0u8..=127).cycle().take(1024).collect();
let (_tmp_dict, dict_path) = make_temp_file(&dict_content);
let data: Vec<u8> = (0u8..=255).cycle().take(65536).collect();
let (_tmp_data, data_path) = make_temp_file(&data);
let config = quiet_config();
let result = bench_files(&[&data_path], 1, 1, Some(&dict_path), &config);
assert!(
result.is_ok(),
"small dict file must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_dict_file_larger_than_max_uses_last_bytes() {
let dict_size = LZ4_MAX_DICT_SIZE + 512;
let dict_content: Vec<u8> = (0u8..=255).cycle().take(dict_size).collect();
let (_tmp_dict, dict_path) = make_temp_file(&dict_content);
let data: Vec<u8> = (0u8..=255).cycle().take(65536).collect();
let (_tmp_data, data_path) = make_temp_file(&data);
let config = quiet_config();
let result = bench_files(&[&data_path], 1, 1, Some(&dict_path), &config);
assert!(
result.is_ok(),
"oversized dict file must succeed (last bytes used): {:?}",
result.err()
);
}
#[test]
fn bench_files_dict_exactly_max_dict_size_ok() {
let dict_content: Vec<u8> = (0u8..=255).cycle().take(LZ4_MAX_DICT_SIZE).collect();
let (_tmp_dict, dict_path) = make_temp_file(&dict_content);
let data: Vec<u8> = b"hello world "
.iter()
.cycle()
.take(65536)
.cloned()
.collect();
let (_tmp_data, data_path) = make_temp_file(&data);
let config = quiet_config();
let result = bench_files(&[&data_path], 1, 1, Some(&dict_path), &config);
assert!(
result.is_ok(),
"dict exactly LZ4_MAX_DICT_SIZE must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_single_file_default_config_ok() {
let data: Vec<u8> = (0u8..=255).cycle().take(65536).collect();
let (_tmp, path) = make_temp_file(&data);
let config = quiet_config();
let result = bench_files(&[&path], 1, 1, None, &config);
assert!(
result.is_ok(),
"single file bench must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_single_file_three_levels_ok() {
let data: Vec<u8> = (0u8..=255).cycle().take(65536).collect();
let (_tmp, path) = make_temp_file(&data);
let mut config = quiet_config();
config.set_notification_level(0);
let result = bench_files(&[&path], 1, 3, None, &config);
assert!(
result.is_ok(),
"3-level file bench must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_multiple_files_combined_ok() {
let data: Vec<u8> = (0u8..=127).cycle().take(32768).collect();
let (_tmp1, path1) = make_temp_file(&data);
let (_tmp2, path2) = make_temp_file(&data);
let config = quiet_config();
let result = bench_files(&[&path1, &path2], 1, 1, None, &config);
assert!(
result.is_ok(),
"multi-file combined bench must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_nonexistent_file_returns_err() {
let config = quiet_config();
let result = bench_files(&["/nonexistent_bench_file_xyz.bin"], 1, 1, None, &config);
assert!(result.is_err(), "nonexistent file must return Err");
}
#[test]
fn bench_files_separately_two_files_ok() {
let data: Vec<u8> = (0u8..=255).cycle().take(4096).collect();
let (_tmp1, path1) = make_temp_file(&data);
let (_tmp2, path2) = make_temp_file(&data);
let mut config = quiet_config();
config.set_bench_separately(true);
let result = bench_files(&[&path1, &path2], 1, 1, None, &config);
assert!(
result.is_ok(),
"bench_separately two files must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_separately_nonexistent_file_returns_err() {
let mut config = quiet_config();
config.set_bench_separately(true);
let result = bench_files(&["/nonexistent_separate_xyz.bin"], 1, 1, None, &config);
assert!(
result.is_err(),
"nonexistent file in separate mode must return Err"
);
}
#[test]
fn bench_files_separately_level_clamped_to_max() {
let data: Vec<u8> = (0u8..=255).cycle().take(4096).collect();
let (_tmp, path) = make_temp_file(&data);
let mut config = quiet_config();
config.set_bench_separately(true);
let result = bench_files(&[&path], 999, 999, None, &config);
assert!(
result.is_ok(),
"over-max level in separate mode must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_files_separately_last_below_first_clamped_ok() {
let data: Vec<u8> = (0u8..=255).cycle().take(4096).collect();
let (_tmp, path) = make_temp_file(&data);
let mut config = quiet_config();
config.set_bench_separately(true);
let result = bench_files(&[&path], 5, 2, None, &config);
assert!(
result.is_ok(),
"clamped c_level_last in separate mode must succeed: {:?}",
result.err()
);
}
#[test]
fn bench_config_re_exported_from_bench_module() {
let _cfg: lz4::bench::BenchConfig = lz4::bench::BenchConfig::default();
}