use super::*;
#[test]
fn test_parse_value_string_literals() {
assert_eq!(
parse_value("\"hello\""),
Ok(("", Value::String("hello".to_string())))
);
assert_eq!(
parse_value("\"ELF\""),
Ok(("", Value::String("ELF".to_string())))
);
assert_eq!(parse_value("\"\""), Ok(("", Value::String(String::new()))));
assert_eq!(
parse_value("\"Line1\\nLine2\""),
Ok(("", Value::String("Line1\nLine2".to_string())))
);
assert_eq!(
parse_value("\"Tab\\tSeparated\""),
Ok(("", Value::String("Tab\tSeparated".to_string())))
);
assert_eq!(
parse_value("\"Null\\0Term\""),
Ok(("", Value::String("Null\0Term".to_string())))
);
}
#[test]
fn test_parse_value_numeric_literals() {
assert_eq!(parse_value("0"), Ok(("", Value::Uint(0))));
assert_eq!(parse_value("123"), Ok(("", Value::Uint(123))));
assert_eq!(parse_value("999"), Ok(("", Value::Uint(999))));
assert_eq!(parse_value("-1"), Ok(("", Value::Int(-1))));
assert_eq!(parse_value("-123"), Ok(("", Value::Int(-123))));
assert_eq!(parse_value("-999"), Ok(("", Value::Int(-999))));
assert_eq!(parse_value("0x0"), Ok(("", Value::Uint(0))));
assert_eq!(parse_value("0x10"), Ok(("", Value::Uint(16))));
assert_eq!(parse_value("0xFF"), Ok(("", Value::Uint(255))));
assert_eq!(parse_value("-0xFF"), Ok(("", Value::Int(-255))));
}
#[test]
fn test_parse_value_hex_byte_sequences() {
assert_eq!(parse_value("\\x7f"), Ok(("", Value::Bytes(vec![0x7f]))));
assert_eq!(
parse_value("\\x7f\\x45\\x4c\\x46"),
Ok(("", Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46])))
);
assert_eq!(parse_value("7f"), Ok(("", Value::Bytes(vec![0x7f]))));
assert_eq!(
parse_value("7f454c46"),
Ok(("", Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46])))
);
assert_eq!(parse_value("aB"), Ok(("", Value::Bytes(vec![0xab]))));
assert_eq!(parse_value("\\xCd"), Ok(("", Value::Bytes(vec![0xcd]))));
}
#[test]
fn test_parse_value_with_whitespace() {
assert_eq!(
parse_value(" \"hello\" "),
Ok(("", Value::String("hello".to_string())))
);
assert_eq!(parse_value(" 123 "), Ok(("", Value::Uint(123))));
assert_eq!(parse_value("\t-456\t"), Ok(("", Value::Int(-456))));
assert_eq!(parse_value(" 3.125 "), Ok(("", Value::Float(3.125))));
assert_eq!(parse_value("\t-1.0\t"), Ok(("", Value::Float(-1.0))));
assert_eq!(
parse_value(" \\x7f\\x45 "),
Ok((" ", Value::Bytes(vec![0x7f, 0x45])))
);
}
#[test]
fn test_parse_value_with_remaining_input() {
assert_eq!(
parse_value("\"hello\" world"),
Ok(("world", Value::String("hello".to_string())))
);
assert_eq!(
parse_value("123 rest"),
Ok(("rest", Value::Uint(123))) );
assert_eq!(
parse_value("-456 more"),
Ok(("more", Value::Int(-456))) );
assert_eq!(
parse_value("\\x7f\\x45 next"),
Ok((" next", Value::Bytes(vec![0x7f, 0x45]))) );
}
#[test]
fn test_parse_value_edge_cases() {
assert_eq!(parse_value("0"), Ok(("", Value::Uint(0))));
assert_eq!(parse_value("-0"), Ok(("", Value::Int(0))));
assert_eq!(parse_value("0x0"), Ok(("", Value::Uint(0))));
assert_eq!(parse_value("-0x0"), Ok(("", Value::Int(0))));
assert_eq!(
parse_value("2147483647"),
Ok(("", Value::Uint(2_147_483_647)))
);
assert_eq!(
parse_value("-2147483648"),
Ok(("", Value::Int(-2_147_483_648)))
);
assert_eq!(
parse_value("0x7FFFFFFF"),
Ok(("", Value::Uint(2_147_483_647)))
);
assert!(parse_value("").is_err());
}
#[test]
fn test_parse_value_invalid_input() {
assert!(parse_value("xyz").is_err()); assert!(parse_value("0xGG").is_err()); assert!(parse_value("\"unclosed").is_err()); assert!(parse_value("--123").is_err()); }
#[test]
fn test_parse_value_common_magic_file_patterns() {
assert_eq!(
parse_value("0x7f454c46"),
Ok(("", Value::Uint(0x7f45_4c46)))
);
assert_eq!(
parse_value("\"ELF\""),
Ok(("", Value::String("ELF".to_string())))
);
assert_eq!(
parse_value("\\x50\\x4b\\x03\\x04"),
Ok(("", Value::Bytes(vec![0x50, 0x4b, 0x03, 0x04])))
);
assert_eq!(
parse_value("\"\\377ELF\""),
Ok(("", Value::String("\u{00ff}ELF".to_string())))
);
assert_eq!(parse_value("0"), Ok(("", Value::Uint(0))));
assert_eq!(parse_value("-1"), Ok(("", Value::Int(-1))));
}
#[test]
fn test_parse_value_type_precedence() {
assert_eq!(
parse_value("\"7f\""),
Ok(("", Value::String("7f".to_string())))
);
assert_eq!(parse_value("7f"), Ok(("", Value::Bytes(vec![0x7f]))));
assert_eq!(parse_value("123"), Ok(("", Value::Uint(123))));
assert_eq!(parse_value("-123"), Ok(("", Value::Int(-123))));
assert_eq!(parse_value("0x123"), Ok(("", Value::Uint(0x123))));
}
#[test]
fn test_parse_value_float_literals() {
assert_eq!(parse_value("3.125"), Ok(("", Value::Float(3.125))));
assert_eq!(parse_value("0.5"), Ok(("", Value::Float(0.5))));
assert_eq!(parse_value("100.0"), Ok(("", Value::Float(100.0))));
assert_eq!(parse_value("-1.0"), Ok(("", Value::Float(-1.0))));
assert_eq!(parse_value("-0.001"), Ok(("", Value::Float(-0.001))));
assert_eq!(parse_value("2.5e10"), Ok(("", Value::Float(2.5e10))));
assert_eq!(parse_value("1.0E-3"), Ok(("", Value::Float(1.0e-3))));
assert_eq!(parse_value("-3.0e+2"), Ok(("", Value::Float(-3.0e+2))));
assert_eq!(parse_value("123"), Ok(("", Value::Uint(123))));
assert_eq!(parse_value("-456"), Ok(("", Value::Int(-456))));
assert_eq!(parse_value("0x1a"), Ok(("", Value::Uint(26))));
assert_eq!(parse_value("1.5 rest"), Ok(("rest", Value::Float(1.5))));
if let Ok((_, value)) = parse_value("1.0e309") {
assert!(
!matches!(value, Value::Float(f) if !f.is_finite()),
"overflow should not produce non-finite Value::Float"
);
}
}
#[test]
fn test_parse_value_boundary_conditions() {
assert_eq!(
parse_value("\"a\""),
Ok(("", Value::String("a".to_string())))
);
assert_eq!(
parse_value("\"1\""),
Ok(("", Value::String("1".to_string())))
);
assert_eq!(parse_value("ab"), Ok(("", Value::Bytes(vec![0xab]))));
assert_eq!(parse_value("\\x00"), Ok(("", Value::Bytes(vec![0x00]))));
assert_eq!(parse_value("1"), Ok(("", Value::Uint(1))));
assert_eq!(parse_value("-1"), Ok(("", Value::Int(-1))));
assert_eq!(parse_value("256"), Ok(("", Value::Uint(256))));
assert_eq!(parse_value("0x100"), Ok(("", Value::Uint(256))));
assert_eq!(parse_value("1024"), Ok(("", Value::Uint(1024))));
assert_eq!(parse_value("0x400"), Ok(("", Value::Uint(1024))));
}
#[test]
fn test_string_family_bareword_numeric_value_parses_as_string() {
let cases: &[(&str, Value, Operator)] = &[
(
"0 string 000 face %s",
Value::String("000".to_string()),
Operator::Equal,
),
(
"0 string >0 \\b, name %s",
Value::String("0".to_string()),
Operator::GreaterThan,
),
(
"0 string >0.6.1 version %s",
Value::String("0.6.1".to_string()),
Operator::GreaterThan,
),
(
"0 string >20011231 date %s",
Value::String("20011231".to_string()),
Operator::GreaterThan,
),
(
"0 string <9 low %s",
Value::String("9".to_string()),
Operator::LessThan,
),
(
"0 search/16 100 hit %s",
Value::String("100".to_string()),
Operator::Equal,
),
];
for (input, expected_value, expected_op) in cases {
let (_, rule) =
parse_magic_rule(input).unwrap_or_else(|e| panic!("parse failed for {input:?}: {e:?}"));
assert_eq!(
rule.value, *expected_value,
"value mismatch for {input:?}: got {:?}",
rule.value
);
assert_eq!(rule.op, *expected_op, "operator mismatch for {input:?}");
}
}
#[test]
fn test_string_family_value_preserves_quoted_and_hex_bytes() {
let (_, rule) = parse_magic_rule("0 string \"0\" literal").unwrap();
assert_eq!(rule.value, Value::String("0".to_string()));
let (_, rule) = parse_magic_rule("0 string \\037\\213 gzip").unwrap();
assert_eq!(rule.value, Value::Bytes(vec![0x1f, 0x8b]));
let (_, rule) = parse_magic_rule("0 string \\177ELF elf").unwrap();
assert_eq!(rule.value, Value::Bytes(vec![0x7f, b'E', b'L', b'F']));
let (_, rule) = parse_magic_rule("0 string >AB thing").unwrap();
assert_eq!(rule.value, Value::Bytes(vec![0xAB]));
}
#[test]
fn parse_bare_string_value_high_byte_returns_bytes_not_lossy_string() {
let cases: &[(&str, Value)] = &[
(
"0 string HSP\\x01\\x9b\\x00 OS/2 INF",
Value::Bytes(vec![0x48, 0x53, 0x50, 0x01, 0x9b, 0x00]),
),
(
"0 string AB\\376 thing",
Value::Bytes(vec![0x41, 0x42, 0xFE]),
),
("0 string HSP header", Value::String("HSP".to_string())),
];
for (input, expected) in cases {
let (_, rule) =
parse_magic_rule(input).unwrap_or_else(|e| panic!("parse failed for {input:?}: {e:?}"));
assert_eq!(
rule.value, *expected,
"value mismatch for {input:?}: got {:?}, expected {expected:?}",
rule.value
);
}
}