use super::*;
#[test]
fn test_search_parent_advances_anchor_to_match_end_not_window_end() {
let child = MagicRule {
offset: OffsetSpec::Relative(0),
typ: TypeKind::Byte { signed: false },
op: Operator::Equal,
value: Value::Uint(u64::from(b'Y')),
message: "trailing Y".to_string(),
children: vec![],
level: 1,
strength_modifier: None,
value_transform: None,
};
let parent = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Search {
range: ::std::num::NonZeroUsize::new(14),
flags: SearchFlags::default(),
},
op: Operator::Equal,
value: Value::String("needle".to_string()),
message: "found needle".to_string(),
children: vec![child],
level: 0,
strength_modifier: None,
value_transform: None,
};
let mut context = EvaluationContext::new(EvaluationConfig::default());
let matches = evaluate_rules(&[parent], b"XXXneedleYY_ZZ", &mut context).unwrap();
assert_eq!(matches.len(), 2, "expected parent + child, got {matches:?}");
assert_eq!(matches[1].message, "trailing Y");
}
#[test]
fn test_search_parent_relative_child_at_positive_offset() {
let child = MagicRule {
offset: OffsetSpec::Relative(1),
typ: TypeKind::Byte { signed: false },
op: Operator::Equal,
value: Value::Uint(u64::from(b'a')),
message: "a after".to_string(),
children: vec![],
level: 1,
strength_modifier: None,
value_transform: None,
};
let parent = MagicRule {
offset: OffsetSpec::Absolute(0),
typ: TypeKind::Search {
range: ::std::num::NonZeroUsize::new(32),
flags: SearchFlags::default(),
},
op: Operator::Equal,
value: Value::String("NEEDLE".to_string()),
message: "found".to_string(),
children: vec![child],
level: 0,
strength_modifier: None,
value_transform: None,
};
let mut context = EvaluationContext::new(EvaluationConfig::default());
let matches = evaluate_rules(&[parent], b"prefix_NEEDLE_after_stuff", &mut context).unwrap();
assert_eq!(matches.len(), 2);
assert_eq!(matches[1].message, "a after");
}
#[test]
fn test_signed_masked_long_matches_macho_signature_end_to_end() {
use crate::parser::grammar::parse_magic_rule;
let (_, rule) = parse_magic_rule("0\tlelong&0xfffffffe\t0xfeedface\tMach-O")
.expect("the Mach-O magic rule must parse");
let buffer = [0xcf_u8, 0xfa, 0xed, 0xfe, 0x0c, 0x00, 0x00, 0x01];
let mut context = EvaluationContext::new(EvaluationConfig::default());
let matches =
evaluate_rules(&[rule], &buffer, &mut context).expect("evaluation must not fatally error");
assert!(
matches.iter().any(|m| m.message.contains("Mach-O")),
"signed lelong&0xfffffffe must detect the Mach-O signature, got: {matches:?}"
);
let (_, rule2) =
parse_magic_rule("0\tlelong&0xfffffffe\t0xfeedface\tMach-O").expect("rule must parse");
let other = [0x12_u8, 0x34, 0x56, 0x78];
let mut ctx2 = EvaluationContext::new(EvaluationConfig::default());
let none = evaluate_rules(&[rule2], &other, &mut ctx2).expect("evaluation must not error");
assert!(
!none.iter().any(|m| m.message.contains("Mach-O")),
"a non-Mach-O buffer must not match the signature"
);
}
#[test]
fn test_string_rule_with_high_byte_value_matches_raw_bytes_end_to_end() {
use crate::parser::grammar::parse_magic_rule;
let (_, rule) = parse_magic_rule("0\tstring\t\\037\\213\tgzip compressed data")
.expect("gzip magic rule must parse");
let buffer = [0x1f_u8, 0x8b, 0x08, 0x00]; let mut context = EvaluationContext::new(EvaluationConfig::default());
let matches =
evaluate_rules(&[rule], &buffer, &mut context).expect("evaluation must not error");
assert!(
matches.iter().any(|m| m.message.contains("gzip")),
"a high-byte string value must match the raw file bytes, got: {matches:?}"
);
let (_, rule2) =
parse_magic_rule("0\tstring\t\\037\\213\tgzip compressed data").expect("rule must parse");
let other = [0x1f_u8, 0x9d, 0x00, 0x00]; let mut ctx2 = EvaluationContext::new(EvaluationConfig::default());
let none = evaluate_rules(&[rule2], &other, &mut ctx2).expect("evaluation must not error");
assert!(
!none.iter().any(|m| m.message.contains("gzip")),
"a non-gzip high byte must not match the gzip signature"
);
}