mod bitwise;
mod comparison;
mod equality;
pub use bitwise::{
apply_bitwise_and, apply_bitwise_and_mask, apply_bitwise_not, apply_bitwise_not_with_width,
apply_bitwise_xor,
};
pub use comparison::{
apply_greater_equal, apply_greater_than, apply_less_equal, apply_less_than, compare_values,
};
pub use equality::{apply_equal, apply_not_equal};
use crate::parser::ast::{Operator, Value};
#[must_use]
pub fn apply_any_value(_left: &Value, _right: &Value) -> bool {
true
}
#[must_use]
pub fn apply_operator(operator: &Operator, left: &Value, right: &Value) -> bool {
match operator {
Operator::Equal => apply_equal(left, right),
Operator::NotEqual => apply_not_equal(left, right),
Operator::LessThan => apply_less_than(left, right),
Operator::GreaterThan => apply_greater_than(left, right),
Operator::LessEqual => apply_less_equal(left, right),
Operator::GreaterEqual => apply_greater_equal(left, right),
Operator::BitwiseAnd => apply_bitwise_and(left, right),
Operator::BitwiseAndMask(mask) => apply_bitwise_and_mask(*mask, left, right),
Operator::BitwiseXor => apply_bitwise_xor(left, right),
Operator::BitwiseNot => apply_bitwise_not(left, right),
Operator::AnyValue => apply_any_value(left, right),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_apply_operator_equal() {
assert!(apply_operator(
&Operator::Equal,
&Value::Uint(42),
&Value::Uint(42)
));
assert!(!apply_operator(
&Operator::Equal,
&Value::Uint(42),
&Value::Uint(24)
));
assert!(apply_operator(
&Operator::Equal,
&Value::String("hello".to_string()),
&Value::String("hello".to_string())
));
assert!(!apply_operator(
&Operator::Equal,
&Value::String("hello".to_string()),
&Value::String("world".to_string())
));
assert!(apply_operator(
&Operator::Equal,
&Value::Uint(42),
&Value::Int(42)
));
}
#[test]
fn test_apply_operator_not_equal() {
assert!(!apply_operator(
&Operator::NotEqual,
&Value::Uint(42),
&Value::Uint(42)
));
assert!(apply_operator(
&Operator::NotEqual,
&Value::Uint(42),
&Value::Uint(24)
));
assert!(!apply_operator(
&Operator::NotEqual,
&Value::String("hello".to_string()),
&Value::String("hello".to_string())
));
assert!(apply_operator(
&Operator::NotEqual,
&Value::String("hello".to_string()),
&Value::String("world".to_string())
));
assert!(!apply_operator(
&Operator::NotEqual,
&Value::Uint(42),
&Value::Int(42)
));
}
#[test]
fn test_apply_operator_bitwise_and() {
assert!(apply_operator(
&Operator::BitwiseAnd,
&Value::Uint(0xFF),
&Value::Uint(0x0F)
));
assert!(!apply_operator(
&Operator::BitwiseAnd,
&Value::Uint(0xF0),
&Value::Uint(0x0F)
));
assert!(apply_operator(
&Operator::BitwiseAnd,
&Value::Int(-1),
&Value::Int(1)
));
assert!(!apply_operator(
&Operator::BitwiseAnd,
&Value::Int(-2),
&Value::Int(1)
));
assert!(apply_operator(
&Operator::BitwiseAnd,
&Value::Uint(0xFF),
&Value::Int(0x0F)
));
assert!(!apply_operator(
&Operator::BitwiseAnd,
&Value::String("test".to_string()),
&Value::Uint(0x01)
));
}
#[test]
fn test_apply_operator_all_operators_with_same_values() {
let test_cases = vec![
(Value::Uint(42), Value::Uint(42)),
(Value::Int(-100), Value::Int(-100)),
(
Value::String("test".to_string()),
Value::String("test".to_string()),
),
(Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
];
for (left, right) in test_cases {
assert!(
apply_operator(&Operator::Equal, &left, &right),
"Equal should be true for same values: {left:?} == {right:?}"
);
assert!(
!apply_operator(&Operator::NotEqual, &left, &right),
"NotEqual should be false for same values: {left:?} != {right:?}"
);
let bitwise_result = apply_operator(&Operator::BitwiseAnd, &left, &right);
match &left {
Value::Uint(n) => {
let expected = *n != 0;
assert_eq!(
bitwise_result, expected,
"BitwiseAnd for Uint({n}) should be {expected}"
);
}
Value::Int(n) => {
let expected = *n != 0;
assert_eq!(
bitwise_result, expected,
"BitwiseAnd for Int({n}) should be {expected}"
);
}
_ => {
assert!(
!bitwise_result,
"BitwiseAnd should be false for non-integer types: {left:?}"
);
}
}
}
}
#[test]
fn test_apply_operator_all_operators_with_different_values() {
let test_cases = vec![
(Value::Uint(42), Value::Uint(24)),
(Value::Int(100), Value::Int(-100)),
(
Value::String("hello".to_string()),
Value::String("world".to_string()),
),
(Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![4, 5, 6])),
(Value::Uint(42), Value::String("42".to_string())),
(Value::Int(42), Value::Bytes(vec![42])),
];
for (left, right) in test_cases {
assert!(
!apply_operator(&Operator::Equal, &left, &right),
"Equal should be false for different values: {left:?} == {right:?}"
);
assert!(
apply_operator(&Operator::NotEqual, &left, &right),
"NotEqual should be true for different values: {left:?} != {right:?}"
);
let bitwise_result = apply_operator(&Operator::BitwiseAnd, &left, &right);
match (&left, &right) {
(Value::Uint(a), Value::Uint(b)) => {
let expected = (a & b) != 0;
assert_eq!(
bitwise_result, expected,
"BitwiseAnd for Uint({a}) & Uint({b}) should be {expected}"
);
}
(Value::Int(a), Value::Int(b)) => {
#[allow(clippy::cast_sign_loss)]
let expected = ((*a as u64) & (*b as u64)) != 0;
assert_eq!(
bitwise_result, expected,
"BitwiseAnd for Int({a}) & Int({b}) should be {expected}"
);
}
(Value::Uint(a), Value::Int(b)) | (Value::Int(b), Value::Uint(a)) => {
#[allow(clippy::cast_sign_loss)]
let expected = (a & (*b as u64)) != 0;
assert_eq!(
bitwise_result, expected,
"BitwiseAnd for mixed Uint/Int should be {expected}"
);
}
_ => {
assert!(
!bitwise_result,
"BitwiseAnd should be false for non-integer types: {left:?} & {right:?}"
);
}
}
}
}
#[test]
fn test_apply_operator_consistency_with_individual_functions() {
let test_cases = vec![
(Value::Uint(42), Value::Uint(42)),
(Value::Uint(42), Value::Uint(24)),
(Value::Int(-100), Value::Int(-100)),
(Value::Int(100), Value::Int(-100)),
(
Value::String("test".to_string()),
Value::String("test".to_string()),
),
(
Value::String("hello".to_string()),
Value::String("world".to_string()),
),
(Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
(Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![4, 5, 6])),
(Value::Uint(42), Value::Int(42)),
(Value::Uint(42), Value::String("42".to_string())),
(Value::Int(42), Value::Bytes(vec![42])),
];
for (left, right) in test_cases {
assert_eq!(
apply_operator(&Operator::Equal, &left, &right),
apply_equal(&left, &right),
"apply_operator(Equal) should match apply_equal for {left:?}, {right:?}"
);
assert_eq!(
apply_operator(&Operator::NotEqual, &left, &right),
apply_not_equal(&left, &right),
"apply_operator(NotEqual) should match apply_not_equal for {left:?}, {right:?}"
);
assert_eq!(
apply_operator(&Operator::BitwiseAnd, &left, &right),
apply_bitwise_and(&left, &right),
"apply_operator(BitwiseAnd) should match apply_bitwise_and for {left:?}, {right:?}"
);
assert_eq!(
apply_operator(&Operator::BitwiseXor, &left, &right),
apply_bitwise_xor(&left, &right),
"apply_operator(BitwiseXor) should match apply_bitwise_xor for {left:?}, {right:?}"
);
assert_eq!(
apply_operator(&Operator::BitwiseNot, &left, &right),
apply_bitwise_not(&left, &right),
"apply_operator(BitwiseNot) should match apply_bitwise_not for {left:?}, {right:?}"
);
assert!(
apply_operator(&Operator::AnyValue, &left, &right),
"apply_operator(AnyValue) should always be true for {left:?}, {right:?}"
);
}
}
#[test]
fn test_apply_operator_magic_rule_scenarios() {
let elf_magic = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
let elf_expected = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
assert!(apply_operator(&Operator::Equal, &elf_magic, &elf_expected));
assert!(!apply_operator(
&Operator::NotEqual,
&elf_magic,
&elf_expected
));
let zip_magic = Value::Uint(0x504B_0304);
let zip_expected = Value::Uint(0x504B_0304);
assert!(apply_operator(&Operator::Equal, &zip_magic, &zip_expected));
let flags = Value::Uint(0b1101_0110);
let flag_mask = Value::Uint(0b0000_0010); assert!(apply_operator(&Operator::BitwiseAnd, &flags, &flag_mask));
let no_flag_mask = Value::Uint(0b0000_0001); assert!(!apply_operator(
&Operator::BitwiseAnd,
&flags,
&no_flag_mask
));
let content = Value::String("#!/bin/bash".to_string());
let shebang = Value::String("#!/bin/bash".to_string());
assert!(apply_operator(&Operator::Equal, &content, &shebang));
let not_shebang = Value::String("#!/usr/bin/python".to_string());
assert!(apply_operator(&Operator::NotEqual, &content, ¬_shebang));
let version = Value::Uint(2);
let expected_version = Value::Uint(2);
let old_version = Value::Uint(1);
assert!(apply_operator(
&Operator::Equal,
&version,
&expected_version
));
assert!(apply_operator(&Operator::NotEqual, &version, &old_version));
}
#[test]
fn test_apply_operator_edge_cases() {
let max_uint = Value::Uint(u64::MAX);
let min_signed = Value::Int(i64::MIN);
let max_signed = Value::Int(i64::MAX);
assert!(apply_operator(&Operator::Equal, &max_uint, &max_uint));
assert!(apply_operator(&Operator::Equal, &min_signed, &min_signed));
assert!(apply_operator(&Operator::Equal, &max_signed, &max_signed));
assert!(apply_operator(&Operator::NotEqual, &max_uint, &min_signed));
assert!(apply_operator(
&Operator::NotEqual,
&max_signed,
&min_signed
));
assert!(apply_operator(
&Operator::BitwiseAnd,
&max_uint,
&Value::Uint(1)
));
assert!(apply_operator(
&Operator::BitwiseAnd,
&min_signed,
&min_signed
));
let empty_bytes = Value::Bytes(vec![]);
let empty_string = Value::String(String::new());
assert!(apply_operator(&Operator::Equal, &empty_bytes, &empty_bytes));
assert!(apply_operator(
&Operator::Equal,
&empty_string,
&empty_string
));
assert!(apply_operator(
&Operator::NotEqual,
&empty_bytes,
&empty_string
));
let zero_uint = Value::Uint(0);
let zero_signed = Value::Int(0);
assert!(!apply_operator(
&Operator::BitwiseAnd,
&zero_uint,
&Value::Uint(0xFF)
));
assert!(!apply_operator(
&Operator::BitwiseAnd,
&zero_signed,
&Value::Int(0xFF)
));
assert!(!apply_operator(
&Operator::NotEqual,
&zero_uint,
&zero_signed
)); }
#[test]
fn test_apply_operator_bitwise_xor() {
assert!(apply_operator(
&Operator::BitwiseXor,
&Value::Uint(0xFF),
&Value::Uint(0x0F)
));
assert!(!apply_operator(
&Operator::BitwiseXor,
&Value::Uint(42),
&Value::Uint(42)
));
assert!(!apply_operator(
&Operator::BitwiseXor,
&Value::String("x".to_string()),
&Value::Uint(1)
));
}
#[test]
fn test_apply_operator_bitwise_not() {
assert!(apply_operator(
&Operator::BitwiseNot,
&Value::Uint(0),
&Value::Uint(u64::MAX)
));
assert!(apply_operator(
&Operator::BitwiseNot,
&Value::Int(-1),
&Value::Int(0)
));
assert!(!apply_operator(
&Operator::BitwiseNot,
&Value::Bytes(vec![0]),
&Value::Uint(0xFF)
));
}
#[test]
fn test_apply_operator_any_value() {
assert!(apply_operator(
&Operator::AnyValue,
&Value::Uint(0),
&Value::Uint(0)
));
assert!(apply_operator(
&Operator::AnyValue,
&Value::Int(42),
&Value::Int(0)
));
assert!(apply_operator(
&Operator::AnyValue,
&Value::Bytes(vec![1, 2, 3]),
&Value::Bytes(vec![])
));
assert!(apply_operator(
&Operator::AnyValue,
&Value::String("x".to_string()),
&Value::String("y".to_string())
));
assert!(apply_operator(
&Operator::AnyValue,
&Value::Uint(1),
&Value::String(String::new())
));
assert!(apply_operator(
&Operator::AnyValue,
&Value::Bytes(vec![]),
&Value::Bytes(vec![])
));
}
#[test]
fn test_apply_operator_all_combinations() {
let operators = [
Operator::Equal,
Operator::NotEqual,
Operator::LessThan,
Operator::GreaterThan,
Operator::LessEqual,
Operator::GreaterEqual,
Operator::BitwiseAnd,
Operator::BitwiseAndMask(0xFF),
Operator::BitwiseXor,
Operator::BitwiseNot,
Operator::AnyValue,
];
let values = [
Value::Uint(42),
Value::Int(-42),
Value::Bytes(vec![42]),
Value::String("42".to_string()),
];
for operator in &operators {
for left in &values {
for right in &values {
let result = apply_operator(operator, left, right);
let expected = match operator {
Operator::Equal => apply_equal(left, right),
Operator::NotEqual => apply_not_equal(left, right),
Operator::LessThan => apply_less_than(left, right),
Operator::GreaterThan => apply_greater_than(left, right),
Operator::LessEqual => apply_less_equal(left, right),
Operator::GreaterEqual => apply_greater_equal(left, right),
Operator::BitwiseAnd => apply_bitwise_and(left, right),
Operator::BitwiseAndMask(mask) => {
apply_bitwise_and_mask(*mask, left, right)
}
Operator::BitwiseXor => apply_bitwise_xor(left, right),
Operator::BitwiseNot => apply_bitwise_not(left, right),
Operator::AnyValue => apply_any_value(left, right),
};
assert_eq!(
result, expected,
"apply_operator({operator:?}, {left:?}, {right:?}) should match individual function"
);
}
}
}
}
}