use super::*;
use crate::EvaluationConfig;
use crate::evaluator::{EvaluationContext, evaluate_rules};
#[test]
fn mixed_escape_and_literal_token_is_captured_whole() {
let (remaining, bytes) = parse_hex_bytes(r"\x41BC[def").expect(r"\x41BC[def");
assert_eq!(remaining, "", "whole token must be consumed, none leaked");
assert_eq!(
bytes,
vec![0x41, b'B', b'C', b'[', b'd', b'e', b'f'],
"all intended bytes must be present, in order"
);
}
#[test]
fn mixed_escape_and_literal_token_stops_only_at_whitespace() {
let (remaining, bytes) =
parse_hex_bytes(r"\x7f\x45(LF)[bracket] trailing").expect("mixed token with brackets");
assert_eq!(remaining, " trailing");
assert_eq!(
bytes,
{
let mut expected = vec![0x7f, 0x45];
expected.extend_from_slice(b"(LF)[bracket]");
expected
},
"escape + arbitrary literal punctuation must all be captured"
);
}
#[test]
fn no_prefix_hex_token_does_not_truncate_at_trailing_non_hex_chars() {
assert!(
parse_hex_bytes("4a[42").is_err(),
"a hex-looking prefix immediately followed by non-hex-digit, \
non-whitespace characters must not silently truncate"
);
assert_eq!(
parse_hex_bytes("4a1b more text"),
Ok((" more text", vec![0x4a, 0x1b]))
);
assert_eq!(parse_hex_bytes("ab\""), Ok(("\"", vec![0xab])));
}
#[test]
fn search_literal_no_prefix_hex_lookalike_round_trips_through_parse_value() {
assert!(parse_value("ab[cd message").is_err());
match parse_value("4a1bcd 0x41 more") {
Ok((remaining, Value::Bytes(bytes))) => {
assert_eq!(remaining, " 0x41 more");
assert_eq!(bytes, vec![0x4a, 0x1b, 0xcd]);
}
other => panic!("expected whitespace-terminated hex bytes, got {other:?}"),
}
}
#[test]
fn search_rule_with_malformed_hex_lookalike_literal_captures_whole_value() {
let input = "0 search/16 ab[cd real message";
let (remaining, rule) = parse_magic_rule(input).expect(input);
assert_eq!(remaining, "");
assert_eq!(
rule.value,
Value::String("ab[cd".to_string()),
"the whole malformed-hex-lookalike token must be captured as one value \
via the bareword string fallback, not truncated to a partial Value::Bytes"
);
assert_eq!(rule.message, "real message");
}
#[test]
fn search_rule_with_malformed_hex_lookalike_literal_matches_buffer_containing_it() {
let input = "0 search/16 ab[cd real message";
let (_, rule) = parse_magic_rule(input).expect(input);
assert_eq!(rule.value, Value::String("ab[cd".to_string()));
let mut context = EvaluationContext::new(EvaluationConfig::default());
let matches = evaluate_rules(std::slice::from_ref(&rule), b"xxab[cdyy", &mut context)
.expect("evaluation must not error");
assert_eq!(
matches.len(),
1,
"the whole 5-byte literal must match when present in the buffer, got {matches:?}"
);
assert_eq!(matches[0].message, "real message");
context.reset();
let no_match = evaluate_rules(std::slice::from_ref(&rule), b"xxab99yy", &mut context)
.expect("evaluation must not error");
assert!(
no_match.is_empty(),
"a buffer containing only the truncated 1-byte prefix must not match, got {no_match:?}"
);
}
#[test]
fn bareword_escaped_space_does_not_truncate_the_token() {
let input = r"0 search/4096 %\ -*-latex-*- LaTeX document text";
let (remaining, rule) = parse_magic_rule(input).expect(input);
assert_eq!(remaining, "");
assert_eq!(
rule.value,
Value::String("% -*-latex-*-".to_string()),
"the escaped space must be a literal space inside the value, not a token terminator"
);
assert_eq!(rule.message, "LaTeX document text");
let mut context = EvaluationContext::new(EvaluationConfig::default());
let hit = evaluate_rules(
std::slice::from_ref(&rule),
b"junk % -*-latex-*- more",
&mut context,
)
.expect("evaluation must not error");
assert_eq!(hit.len(), 1, "must match when the full pattern is present");
assert_eq!(hit[0].message, "LaTeX document text");
context.reset();
let miss = evaluate_rules(
std::slice::from_ref(&rule),
b"100% binary \x1f\x8b data with a percent",
&mut context,
)
.expect("evaluation must not error");
assert!(
miss.is_empty(),
"a buffer with a bare `%` (but not the full pattern) must NOT match, got {miss:?}"
);
}
#[test]
fn bareword_value_beginning_with_backslash_resolves_full_token_and_matches_xml() {
let input = r"0 string \<?xml\ version= XML document text";
let (remaining, rule) = parse_magic_rule(input).expect(input);
assert_eq!(remaining, "");
assert_eq!(
rule.value,
Value::Bytes(b"<?xml version=".to_vec()),
"the whole getstr-resolved pattern must be captured: `\\<` drops the \
backslash and `\\ ` is a literal space that does not terminate the token"
);
assert_eq!(rule.message, "XML document text");
let mut context = EvaluationContext::new(EvaluationConfig::default());
let hit = evaluate_rules(
std::slice::from_ref(&rule),
br#"<?xml version="1.0" encoding="UTF-8"?>"#,
&mut context,
)
.expect("evaluation must not error");
assert_eq!(hit.len(), 1, "a real <?xml document must match");
assert_eq!(hit[0].message, "XML document text");
context.reset();
let miss = evaluate_rules(
std::slice::from_ref(&rule),
b"plain ASCII text with no xml prolog",
&mut context,
)
.expect("evaluation must not error");
assert!(
miss.is_empty(),
"a non-XML text buffer must NOT match, got {miss:?}"
);
}