use std::fs;
use std::io::Write;
use libmagic_rs::{EvaluationConfig, MagicDatabase};
use tempfile::TempDir;
#[test]
fn test_searchbug_magic_loads_end_to_end() {
let db = MagicDatabase::load_from_file("third_party/tests/searchbug.magic")
.expect("searchbug.magic must load end-to-end");
let bytes = std::fs::read("third_party/tests/searchbug.testfile")
.expect("searchbug.testfile fixture must exist");
let result = db
.evaluate_buffer(&bytes)
.expect("evaluate_buffer on searchbug.testfile");
assert!(
!result.description.is_empty(),
"evaluation should produce some description"
);
assert!(
result.description.starts_with("Testfmt"),
"description should start with \"Testfmt\", got: {}",
result.description
);
}
#[test]
fn test_default_clear_synthetic_scenario() {
let temp_dir = TempDir::new().unwrap();
let magic_path = temp_dir.path().join("default.magic");
let mut f = fs::File::create(&magic_path).unwrap();
writeln!(f, r#"0 byte 0xAA Real-Match"#).unwrap();
writeln!(f, r#"0 default x DEFAULT-FALLBACK"#).unwrap();
let db = MagicDatabase::load_from_file(&magic_path).unwrap();
let buf_no_match = [0x00u8, 0x01, 0x02, 0x03];
let result_default = db.evaluate_buffer(&buf_no_match).unwrap();
assert!(
result_default.description.contains("DEFAULT-FALLBACK"),
"default should fire when no sibling matched, got: {}",
result_default.description
);
let buf_match = [0xAAu8, 0x01, 0x02, 0x03];
let result_real = db.evaluate_buffer(&buf_match).unwrap();
assert!(
!result_real.description.contains("DEFAULT-FALLBACK"),
"default must not fire when a sibling matched, got: {}",
result_real.description
);
assert!(
result_real.description.contains("Real-Match"),
"real byte rule should still match, got: {}",
result_real.description
);
let clear_path = temp_dir.path().join("clear.magic");
let mut cf = fs::File::create(&clear_path).unwrap();
writeln!(cf, r#"0 byte 0xAA Match-A"#).unwrap();
writeln!(cf, r#"0 default x DEFAULT-SKIPPED"#).unwrap();
writeln!(cf, r#"0 clear"#).unwrap();
writeln!(cf, r#"0 default x DEFAULT-FIRES"#).unwrap();
let all_matches_config = EvaluationConfig::default().with_stop_at_first_match(false);
let clear_db =
MagicDatabase::load_from_file_with_config(&clear_path, all_matches_config).unwrap();
let buf_clear = [0xAAu8, 0x01, 0x02, 0x03];
let result_clear = clear_db.evaluate_buffer(&buf_clear).unwrap();
assert!(
result_clear.description.contains("Match-A"),
"byte rule should still match before clear, got: {}",
result_clear.description
);
assert!(
!result_clear.description.contains("DEFAULT-SKIPPED"),
"default immediately after a sibling match must remain silent, got: {}",
result_clear.description
);
assert!(
result_clear.description.contains("DEFAULT-FIRES"),
"clear must reset sibling-matched so a later default can fire, got: {}",
result_clear.description
);
}
#[test]
fn test_indirect_synthetic_scenario() {
let temp_dir = TempDir::new().unwrap();
let magic_path = temp_dir.path().join("indirect.magic");
let mut f = fs::File::create(&magic_path).unwrap();
writeln!(f, r#"0 byte 0x42 Inner-Match"#).unwrap();
writeln!(f, r#"8 indirect x"#).unwrap();
let db = MagicDatabase::load_from_file(&magic_path).unwrap();
let mut buf = vec![0u8; 16];
buf[8] = 0x42;
let result = db.evaluate_buffer(&buf).unwrap();
assert!(
result.description.contains("Inner-Match"),
"indirect must dispatch root rules at the resolved offset; got: {}",
result.description
);
}
#[test]
fn test_searchbug_matches_full_result_string() {
let config = EvaluationConfig::default().with_stop_at_first_match(false);
let db = MagicDatabase::load_from_file_with_config("third_party/tests/searchbug.magic", config)
.expect("searchbug.magic must load end-to-end");
let bytes = std::fs::read("third_party/tests/searchbug.testfile")
.expect("searchbug.testfile fixture must exist");
let expected = std::fs::read_to_string("third_party/tests/searchbug.result")
.expect("searchbug.result fixture must exist");
let result = db
.evaluate_buffer(&bytes)
.expect("evaluate_buffer on searchbug.testfile");
assert_eq!(result.description.trim(), expected.trim());
}