include!(concat!(env!("OUT_DIR"), "/builtin_rules.rs"));
pub fn get_builtin_rules() -> Vec<crate::parser::ast::MagicRule> {
BUILTIN_RULES.clone()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rules_load_successfully() {
let rules = get_builtin_rules();
assert!(!rules.is_empty(), "Built-in rules should not be empty");
}
#[test]
fn test_rules_contain_expected_file_types() {
let rules = get_builtin_rules();
let contains_pattern = |pattern: &str| -> bool {
rules.iter().any(|rule| {
rule.message
.to_lowercase()
.contains(&pattern.to_lowercase())
})
};
assert!(
contains_pattern("ELF"),
"Built-in rules should contain ELF detection"
);
assert!(
contains_pattern("MS-DOS") || contains_pattern("executable"),
"Built-in rules should contain PE/DOS detection"
);
assert!(
contains_pattern("ZIP"),
"Built-in rules should contain ZIP detection"
);
assert!(
contains_pattern("tar"),
"Built-in rules should contain TAR detection"
);
assert!(
contains_pattern("gzip"),
"Built-in rules should contain GZIP detection"
);
assert!(
contains_pattern("JPEG") || contains_pattern("JFIF"),
"Built-in rules should contain JPEG detection"
);
assert!(
contains_pattern("PNG"),
"Built-in rules should contain PNG detection"
);
assert!(
contains_pattern("GIF"),
"Built-in rules should contain GIF detection"
);
assert!(
contains_pattern("BMP") || contains_pattern("bitmap"),
"Built-in rules should contain BMP detection"
);
assert!(
contains_pattern("PDF"),
"Built-in rules should contain PDF detection"
);
}
#[test]
fn test_rules_have_valid_structure() {
let rules = get_builtin_rules();
for (idx, rule) in rules.iter().enumerate() {
assert!(
!rule.message.is_empty(),
"Rule {idx} should have a non-empty message"
);
match &rule.offset {
crate::parser::ast::OffsetSpec::Absolute(offset) => {
assert!(
*offset < 10_000_000,
"Rule {idx} has unreasonably large absolute offset: {offset}"
);
}
crate::parser::ast::OffsetSpec::Indirect { base_offset, .. } => {
assert!(
*base_offset < 10_000_000,
"Rule {idx} has unreasonably large indirect base offset: {base_offset}"
);
}
crate::parser::ast::OffsetSpec::Relative(offset) => {
assert!(
offset.abs() < 10_000_000,
"Rule {idx} has unreasonably large relative offset: {offset}"
);
}
crate::parser::ast::OffsetSpec::FromEnd(offset) => {
assert!(
offset.abs() < 10_000_000,
"Rule {idx} has unreasonably large from-end offset: {offset}"
);
}
}
for child in &rule.children {
assert!(
child.level > rule.level,
"Child rule level should be greater than parent level"
);
}
}
}
#[test]
fn test_lazylock_initialization() {
let rules1 = get_builtin_rules();
let rules2 = get_builtin_rules();
let rules3 = get_builtin_rules();
assert_eq!(
rules1.len(),
rules2.len(),
"Multiple calls should return same number of rules"
);
assert_eq!(
rules2.len(),
rules3.len(),
"Multiple calls should return same number of rules"
);
assert_ne!(
rules1.as_ptr(),
rules2.as_ptr(),
"Each call should return a new Vec (cloned)"
);
}
#[test]
fn test_lazylock_thread_safety() {
use std::thread;
let handles: Vec<_> = (0..10)
.map(|_| {
thread::spawn(|| {
let rules = get_builtin_rules();
rules.len()
})
})
.collect();
let results: Vec<usize> = handles
.into_iter()
.map(|h| h.join().expect("Thread should not panic"))
.collect();
let first_count = results[0];
assert!(
results.iter().all(|&count| count == first_count),
"All threads should see the same number of rules"
);
}
}