Skip to main content

libmagic_rs/evaluator/
operators.rs

1// Copyright (c) 2025-2026 the libmagic-rs contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Operator application for magic rule evaluation
5//!
6//! This module provides functions for applying comparison and bitwise operators
7//! to values during magic rule evaluation. It handles type-safe comparisons
8//! between different Value variants.
9
10use std::cmp::Ordering;
11
12use crate::parser::ast::{Operator, Value};
13
14/// Apply equality comparison between two values
15///
16/// Compares two `Value` instances for equality, handling proper type matching.
17/// Cross-type integer comparisons (`Uint` vs `Int`) are supported via `i128`
18/// coercion. Incompatible types (e.g., string vs integer) are considered unequal.
19///
20/// # Arguments
21///
22/// * `left` - The left-hand side value (typically from file data)
23/// * `right` - The right-hand side value (typically from magic rule)
24///
25/// # Returns
26///
27/// `true` if the values are equal (including cross-type integer coercion), `false` otherwise
28///
29/// # Examples
30///
31/// ```
32/// use libmagic_rs::parser::ast::Value;
33/// use libmagic_rs::evaluator::operators::apply_equal;
34///
35/// // Same type, same value
36/// assert!(apply_equal(&Value::Uint(42), &Value::Uint(42)));
37///
38/// // Same type, different value
39/// assert!(!apply_equal(&Value::Uint(42), &Value::Uint(24)));
40///
41/// // Cross-type integer coercion
42/// assert!(apply_equal(&Value::Uint(42), &Value::Int(42)));
43///
44/// // String comparison
45/// assert!(apply_equal(
46///     &Value::String("hello".to_string()),
47///     &Value::String("hello".to_string())
48/// ));
49/// ```
50#[must_use]
51pub fn apply_equal(left: &Value, right: &Value) -> bool {
52    compare_values(left, right) == Some(Ordering::Equal)
53}
54
55/// Apply inequality comparison between two values
56///
57/// Compares two `Value` instances for inequality, implementing the negation
58/// of equality comparison logic. Returns `true` if the values are not equal
59/// or are of different types.
60///
61/// # Arguments
62///
63/// * `left` - The left-hand side value (typically from file data)
64/// * `right` - The right-hand side value (typically from magic rule)
65///
66/// # Returns
67///
68/// `true` if the values are not equal or of different types, `false` if they are equal
69///
70/// # Examples
71///
72/// ```
73/// use libmagic_rs::parser::ast::Value;
74/// use libmagic_rs::evaluator::operators::apply_not_equal;
75///
76/// // Same type, different value
77/// assert!(apply_not_equal(&Value::Uint(42), &Value::Uint(24)));
78///
79/// // Same type, same value
80/// assert!(!apply_not_equal(&Value::Uint(42), &Value::Uint(42)));
81///
82/// // Cross-type integers with same numeric value (equal via coercion)
83/// assert!(!apply_not_equal(&Value::Uint(42), &Value::Int(42)));
84///
85/// // String comparison
86/// assert!(apply_not_equal(
87///     &Value::String("hello".to_string()),
88///     &Value::String("world".to_string())
89/// ));
90/// ```
91#[must_use]
92pub fn apply_not_equal(left: &Value, right: &Value) -> bool {
93    !apply_equal(left, right)
94}
95
96/// Apply bitwise AND operation for pattern matching
97///
98/// Performs bitwise AND operation between two integer values for pattern matching.
99/// This is commonly used in magic rules to check if specific bits are set in a value.
100/// Only works with integer types (Uint and Int), returns `false` for other types.
101///
102/// # Arguments
103///
104/// * `left` - The left-hand side value (typically from file data)
105/// * `right` - The right-hand side value (typically the mask from magic rule)
106///
107/// # Returns
108///
109/// `true` if the bitwise AND result is non-zero, `false` otherwise or for non-integer types
110///
111/// # Examples
112///
113/// ```
114/// use libmagic_rs::parser::ast::Value;
115/// use libmagic_rs::evaluator::operators::apply_bitwise_and;
116///
117/// // Check if bit 0 is set
118/// assert!(apply_bitwise_and(&Value::Uint(0x01), &Value::Uint(0x01)));
119/// assert!(!apply_bitwise_and(&Value::Uint(0x02), &Value::Uint(0x01)));
120///
121/// // Check multiple bits
122/// assert!(apply_bitwise_and(&Value::Uint(0xFF), &Value::Uint(0x0F)));
123/// assert!(!apply_bitwise_and(&Value::Uint(0xF0), &Value::Uint(0x0F)));
124///
125/// // Works with signed integers too
126/// assert!(apply_bitwise_and(&Value::Int(-1), &Value::Int(0x01)));
127///
128/// // Non-integer types return false
129/// assert!(!apply_bitwise_and(&Value::String("test".to_string()), &Value::Uint(0x01)));
130/// ```
131#[must_use]
132pub fn apply_bitwise_and(left: &Value, right: &Value) -> bool {
133    match (left, right) {
134        // Unsigned integer bitwise AND
135        (Value::Uint(a), Value::Uint(b)) => (a & b) != 0,
136
137        // Signed integer bitwise AND (cast to unsigned for bitwise operations)
138        #[allow(clippy::cast_sign_loss)]
139        (Value::Int(a), Value::Int(b)) => ((*a as u64) & (*b as u64)) != 0,
140
141        // Mixed signed/unsigned integer bitwise AND
142        #[allow(clippy::cast_sign_loss)]
143        (Value::Uint(a), Value::Int(b)) => (a & (*b as u64)) != 0,
144        #[allow(clippy::cast_sign_loss)]
145        (Value::Int(a), Value::Uint(b)) => ((*a as u64) & b) != 0,
146
147        // Non-integer types cannot perform bitwise AND
148        _ => false,
149    }
150}
151
152/// Compare two values and return their ordering, if comparable
153///
154/// Returns `Some(Ordering)` for same-type comparisons (integers, strings, bytes)
155/// and cross-type integer comparisons (via `i128` coercion). Returns `None` for
156/// incomparable type combinations.
157///
158/// # Examples
159///
160/// ```
161/// use std::cmp::Ordering;
162/// use libmagic_rs::parser::ast::Value;
163/// use libmagic_rs::evaluator::operators::compare_values;
164///
165/// assert_eq!(compare_values(&Value::Uint(5), &Value::Uint(10)), Some(Ordering::Less));
166/// assert_eq!(compare_values(&Value::Int(-1), &Value::Uint(0)), Some(Ordering::Less));
167/// assert_eq!(compare_values(&Value::Uint(42), &Value::Int(42)), Some(Ordering::Equal));
168/// assert_eq!(compare_values(&Value::Uint(1), &Value::String("1".to_string())), None);
169/// ```
170#[must_use]
171pub fn compare_values(left: &Value, right: &Value) -> Option<Ordering> {
172    match (left, right) {
173        (Value::Uint(a), Value::Uint(b)) => Some(a.cmp(b)),
174        (Value::Int(a), Value::Int(b)) => Some(a.cmp(b)),
175        (Value::Uint(a), Value::Int(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
176        (Value::Int(a), Value::Uint(b)) => Some(i128::from(*a).cmp(&i128::from(*b))),
177        (Value::String(a), Value::String(b)) => Some(a.cmp(b)),
178        (Value::Bytes(a), Value::Bytes(b)) => Some(a.cmp(b)),
179        _ => None,
180    }
181}
182
183/// Apply less-than comparison between two values
184///
185/// # Examples
186///
187/// ```
188/// use libmagic_rs::parser::ast::Value;
189/// use libmagic_rs::evaluator::operators::apply_less_than;
190///
191/// assert!(apply_less_than(&Value::Uint(5), &Value::Uint(10)));
192/// assert!(!apply_less_than(&Value::Uint(10), &Value::Uint(10)));
193/// assert!(apply_less_than(&Value::Int(-1), &Value::Uint(0)));
194/// ```
195#[must_use]
196pub fn apply_less_than(left: &Value, right: &Value) -> bool {
197    compare_values(left, right) == Some(Ordering::Less)
198}
199
200/// Apply greater-than comparison between two values
201///
202/// # Examples
203///
204/// ```
205/// use libmagic_rs::parser::ast::Value;
206/// use libmagic_rs::evaluator::operators::apply_greater_than;
207///
208/// assert!(apply_greater_than(&Value::Uint(10), &Value::Uint(5)));
209/// assert!(!apply_greater_than(&Value::Uint(10), &Value::Uint(10)));
210/// assert!(apply_greater_than(&Value::Uint(0), &Value::Int(-1)));
211/// ```
212#[must_use]
213pub fn apply_greater_than(left: &Value, right: &Value) -> bool {
214    compare_values(left, right) == Some(Ordering::Greater)
215}
216
217/// Apply less-than-or-equal comparison between two values
218///
219/// # Examples
220///
221/// ```
222/// use libmagic_rs::parser::ast::Value;
223/// use libmagic_rs::evaluator::operators::apply_less_equal;
224///
225/// assert!(apply_less_equal(&Value::Uint(10), &Value::Uint(10)));
226/// assert!(apply_less_equal(&Value::Uint(5), &Value::Uint(10)));
227/// assert!(!apply_less_equal(&Value::Uint(10), &Value::Uint(5)));
228/// ```
229#[must_use]
230pub fn apply_less_equal(left: &Value, right: &Value) -> bool {
231    matches!(
232        compare_values(left, right),
233        Some(Ordering::Less | Ordering::Equal)
234    )
235}
236
237/// Apply greater-than-or-equal comparison between two values
238///
239/// # Examples
240///
241/// ```
242/// use libmagic_rs::parser::ast::Value;
243/// use libmagic_rs::evaluator::operators::apply_greater_equal;
244///
245/// assert!(apply_greater_equal(&Value::Uint(10), &Value::Uint(10)));
246/// assert!(apply_greater_equal(&Value::Uint(10), &Value::Uint(5)));
247/// assert!(!apply_greater_equal(&Value::Uint(5), &Value::Uint(10)));
248/// ```
249#[must_use]
250pub fn apply_greater_equal(left: &Value, right: &Value) -> bool {
251    matches!(
252        compare_values(left, right),
253        Some(Ordering::Greater | Ordering::Equal)
254    )
255}
256
257/// Apply operator to two values using the specified operator type
258///
259/// This is the main operator application interface that dispatches to the appropriate
260/// operator function based on the `Operator` enum variant. This function serves as
261/// the primary entry point for operator evaluation in magic rule processing.
262///
263/// # Arguments
264///
265/// * `operator` - The operator to apply (`Equal`, `NotEqual`, `LessThan`,
266///   `GreaterThan`, `LessEqual`, `GreaterEqual`, `BitwiseAnd`, or `BitwiseAndMask`)
267/// * `left` - The left-hand side value (typically from file data)
268/// * `right` - The right-hand side value (typically from magic rule)
269///
270/// # Returns
271///
272/// `true` if the operator condition is satisfied, `false` otherwise
273///
274/// # Examples
275///
276/// ```
277/// use libmagic_rs::parser::ast::{Operator, Value};
278/// use libmagic_rs::evaluator::operators::apply_operator;
279///
280/// // Equality comparison
281/// assert!(apply_operator(
282///     &Operator::Equal,
283///     &Value::Uint(42),
284///     &Value::Uint(42)
285/// ));
286///
287/// // Inequality comparison
288/// assert!(apply_operator(
289///     &Operator::NotEqual,
290///     &Value::Uint(42),
291///     &Value::Uint(24)
292/// ));
293///
294/// // Less-than comparison
295/// assert!(apply_operator(
296///     &Operator::LessThan,
297///     &Value::Uint(5),
298///     &Value::Uint(10)
299/// ));
300///
301/// // Greater-than comparison
302/// assert!(apply_operator(
303///     &Operator::GreaterThan,
304///     &Value::Uint(10),
305///     &Value::Uint(5)
306/// ));
307///
308/// // Less-than-or-equal comparison
309/// assert!(apply_operator(
310///     &Operator::LessEqual,
311///     &Value::Uint(10),
312///     &Value::Uint(10)
313/// ));
314///
315/// // Greater-than-or-equal comparison
316/// assert!(apply_operator(
317///     &Operator::GreaterEqual,
318///     &Value::Uint(10),
319///     &Value::Uint(10)
320/// ));
321///
322/// // Bitwise AND operation
323/// assert!(apply_operator(
324///     &Operator::BitwiseAnd,
325///     &Value::Uint(0xFF),
326///     &Value::Uint(0x0F)
327/// ));
328///
329/// // Cross-type integer coercion
330/// assert!(apply_operator(
331///     &Operator::Equal,
332///     &Value::Uint(42),
333///     &Value::Int(42)
334/// ));
335/// ```
336#[must_use]
337pub fn apply_operator(operator: &Operator, left: &Value, right: &Value) -> bool {
338    match operator {
339        Operator::Equal => apply_equal(left, right),
340        Operator::NotEqual => apply_not_equal(left, right),
341        Operator::LessThan => apply_less_than(left, right),
342        Operator::GreaterThan => apply_greater_than(left, right),
343        Operator::LessEqual => apply_less_equal(left, right),
344        Operator::GreaterEqual => apply_greater_equal(left, right),
345        Operator::BitwiseAnd => apply_bitwise_and(left, right),
346        Operator::BitwiseAndMask(mask) => {
347            // Apply mask to left value, then compare with right
348            let masked_left = match left {
349                Value::Uint(val) => Value::Uint(val & mask),
350                Value::Int(val) => {
351                    // Convert u64 mask to i64, using bitwise representation for values > i64::MAX
352                    let i64_mask = i64::try_from(*mask)
353                        .unwrap_or_else(|_| i64::from_ne_bytes(mask.to_ne_bytes()));
354                    Value::Int(val & i64_mask)
355                }
356                _ => return false, // Can't apply bitwise operations to non-numeric values
357            };
358            apply_equal(&masked_left, right)
359        }
360    }
361}
362
363#[cfg(test)]
364mod tests {
365    use super::*;
366
367    #[test]
368    fn test_apply_equal_uint_same_value() {
369        let left = Value::Uint(42);
370        let right = Value::Uint(42);
371        assert!(apply_equal(&left, &right));
372    }
373
374    #[test]
375    fn test_apply_equal_uint_different_value() {
376        let left = Value::Uint(42);
377        let right = Value::Uint(24);
378        assert!(!apply_equal(&left, &right));
379    }
380
381    #[test]
382    fn test_apply_equal_uint_zero() {
383        let left = Value::Uint(0);
384        let right = Value::Uint(0);
385        assert!(apply_equal(&left, &right));
386    }
387
388    #[test]
389    fn test_apply_equal_uint_max_value() {
390        let left = Value::Uint(u64::MAX);
391        let right = Value::Uint(u64::MAX);
392        assert!(apply_equal(&left, &right));
393    }
394
395    #[test]
396    fn test_apply_equal_int_same_value() {
397        let left = Value::Int(42);
398        let right = Value::Int(42);
399        assert!(apply_equal(&left, &right));
400    }
401
402    #[test]
403    fn test_apply_equal_int_different_value() {
404        let left = Value::Int(42);
405        let right = Value::Int(-42);
406        assert!(!apply_equal(&left, &right));
407    }
408
409    #[test]
410    fn test_apply_equal_int_negative() {
411        let left = Value::Int(-100);
412        let right = Value::Int(-100);
413        assert!(apply_equal(&left, &right));
414    }
415
416    #[test]
417    fn test_apply_equal_int_zero() {
418        let left = Value::Int(0);
419        let right = Value::Int(0);
420        assert!(apply_equal(&left, &right));
421    }
422
423    #[test]
424    fn test_apply_equal_int_extreme_values() {
425        let left = Value::Int(i64::MAX);
426        let right = Value::Int(i64::MAX);
427        assert!(apply_equal(&left, &right));
428
429        let left = Value::Int(i64::MIN);
430        let right = Value::Int(i64::MIN);
431        assert!(apply_equal(&left, &right));
432    }
433
434    #[test]
435    fn test_apply_equal_bytes_same_value() {
436        let left = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
437        let right = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
438        assert!(apply_equal(&left, &right));
439    }
440
441    #[test]
442    fn test_apply_equal_bytes_different_value() {
443        let left = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
444        let right = Value::Bytes(vec![0x50, 0x4b, 0x03, 0x04]);
445        assert!(!apply_equal(&left, &right));
446    }
447
448    #[test]
449    fn test_apply_equal_bytes_empty() {
450        let left = Value::Bytes(vec![]);
451        let right = Value::Bytes(vec![]);
452        assert!(apply_equal(&left, &right));
453    }
454
455    #[test]
456    fn test_apply_equal_bytes_different_length() {
457        let left = Value::Bytes(vec![0x7f, 0x45]);
458        let right = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
459        assert!(!apply_equal(&left, &right));
460    }
461
462    #[test]
463    fn test_apply_equal_bytes_single_byte() {
464        let left = Value::Bytes(vec![0x7f]);
465        let right = Value::Bytes(vec![0x7f]);
466        assert!(apply_equal(&left, &right));
467
468        let left = Value::Bytes(vec![0x7f]);
469        let right = Value::Bytes(vec![0x45]);
470        assert!(!apply_equal(&left, &right));
471    }
472
473    #[test]
474    fn test_apply_equal_string_same_value() {
475        let left = Value::String("hello".to_string());
476        let right = Value::String("hello".to_string());
477        assert!(apply_equal(&left, &right));
478    }
479
480    #[test]
481    fn test_apply_equal_string_different_value() {
482        let left = Value::String("hello".to_string());
483        let right = Value::String("world".to_string());
484        assert!(!apply_equal(&left, &right));
485    }
486
487    #[test]
488    fn test_apply_equal_string_empty() {
489        let left = Value::String(String::new());
490        let right = Value::String(String::new());
491        assert!(apply_equal(&left, &right));
492    }
493
494    #[test]
495    fn test_apply_equal_string_case_sensitive() {
496        let left = Value::String("Hello".to_string());
497        let right = Value::String("hello".to_string());
498        assert!(!apply_equal(&left, &right));
499    }
500
501    #[test]
502    fn test_apply_equal_string_unicode() {
503        let left = Value::String("🦀 Rust".to_string());
504        let right = Value::String("🦀 Rust".to_string());
505        assert!(apply_equal(&left, &right));
506
507        let left = Value::String("🦀 Rust".to_string());
508        let right = Value::String("🐍 Python".to_string());
509        assert!(!apply_equal(&left, &right));
510    }
511
512    #[test]
513    fn test_apply_equal_string_whitespace() {
514        let left = Value::String("hello world".to_string());
515        let right = Value::String("hello world".to_string());
516        assert!(apply_equal(&left, &right));
517
518        let left = Value::String("hello world".to_string());
519        let right = Value::String("hello  world".to_string()); // Extra space
520        assert!(!apply_equal(&left, &right));
521    }
522
523    // Cross-type comparison tests (should all return false)
524    #[test]
525    fn test_apply_equal_uint_vs_int() {
526        // Same numeric value across types should match
527        let left = Value::Uint(42);
528        let right = Value::Int(42);
529        assert!(apply_equal(&left, &right));
530
531        let left = Value::Uint(0);
532        let right = Value::Int(0);
533        assert!(apply_equal(&left, &right));
534
535        // Negative Int cannot equal Uint
536        let left = Value::Uint(42);
537        let right = Value::Int(-42);
538        assert!(!apply_equal(&left, &right));
539
540        // Large Uint that doesn't fit in i64 cannot equal Int
541        let left = Value::Uint(u64::MAX);
542        let right = Value::Int(-1);
543        assert!(!apply_equal(&left, &right));
544    }
545
546    #[test]
547    fn test_apply_equal_uint_vs_bytes() {
548        let left = Value::Uint(42);
549        let right = Value::Bytes(vec![42]);
550        assert!(!apply_equal(&left, &right));
551    }
552
553    #[test]
554    fn test_apply_equal_uint_vs_string() {
555        let left = Value::Uint(42);
556        let right = Value::String("42".to_string());
557        assert!(!apply_equal(&left, &right));
558    }
559
560    #[test]
561    fn test_apply_equal_int_vs_bytes() {
562        let left = Value::Int(-42);
563        let right = Value::Bytes(vec![214]); // -42 as u8
564        assert!(!apply_equal(&left, &right));
565    }
566
567    #[test]
568    fn test_apply_equal_int_vs_string() {
569        let left = Value::Int(-42);
570        let right = Value::String("-42".to_string());
571        assert!(!apply_equal(&left, &right));
572    }
573
574    #[test]
575    fn test_apply_equal_bytes_vs_string() {
576        let left = Value::Bytes(vec![104, 101, 108, 108, 111]); // "hello" as bytes
577        let right = Value::String("hello".to_string());
578        assert!(!apply_equal(&left, &right));
579    }
580
581    #[test]
582    fn test_apply_equal_all_cross_type_combinations() {
583        let values = [
584            Value::Uint(42),
585            Value::Int(42),
586            Value::Bytes(vec![42]),
587            Value::String("42".to_string()),
588        ];
589
590        // Test cross-type comparisons
591        for (i, left) in values.iter().enumerate() {
592            for (j, right) in values.iter().enumerate() {
593                if i != j {
594                    let result = apply_equal(left, right);
595                    // Uint(42) and Int(42) should be equal (cross-type coercion)
596                    if (i <= 1) && (j <= 1) {
597                        assert!(
598                            result,
599                            "Integer cross-type comparison should be true: {left:?} vs {right:?}"
600                        );
601                    } else {
602                        assert!(
603                            !result,
604                            "Non-integer cross-type comparison should be false: {left:?} vs {right:?}"
605                        );
606                    }
607                }
608            }
609        }
610    }
611
612    #[test]
613    fn test_apply_equal_reflexivity() {
614        let values = vec![
615            Value::Uint(42),
616            Value::Int(-42),
617            Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
618            Value::String("hello".to_string()),
619        ];
620
621        // Test that all values are equal to themselves
622        for value in values {
623            assert!(
624                apply_equal(&value, &value),
625                "Value should be equal to itself: {value:?}"
626            );
627        }
628    }
629
630    #[test]
631    fn test_apply_equal_symmetry() {
632        let test_cases = vec![
633            (Value::Uint(42), Value::Uint(42)),
634            (Value::Int(-100), Value::Int(-100)),
635            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
636            (
637                Value::String("test".to_string()),
638                Value::String("test".to_string()),
639            ),
640        ];
641
642        // Test that equality is symmetric: a == b implies b == a
643        for (left, right) in test_cases {
644            let left_to_right = apply_equal(&left, &right);
645            let right_to_left = apply_equal(&right, &left);
646            assert_eq!(
647                left_to_right, right_to_left,
648                "Equality should be symmetric: {left:?} vs {right:?}"
649            );
650        }
651    }
652
653    #[test]
654    fn test_apply_equal_transitivity() {
655        // Test transitivity: if a == b and b == c, then a == c
656        let a = Value::Uint(123);
657        let b = Value::Uint(123);
658        let c = Value::Uint(123);
659
660        assert!(apply_equal(&a, &b));
661        assert!(apply_equal(&b, &c));
662        assert!(apply_equal(&a, &c));
663    }
664
665    #[test]
666    fn test_apply_equal_edge_cases() {
667        // Test with maximum values
668        let max_unsigned = Value::Uint(u64::MAX);
669        let max_signed = Value::Int(i64::MAX);
670        let min_int = Value::Int(i64::MIN);
671
672        assert!(apply_equal(&max_unsigned, &max_unsigned));
673        assert!(apply_equal(&max_signed, &max_signed));
674        assert!(apply_equal(&min_int, &min_int));
675
676        // Cross-type edge cases
677        // u64::MAX != -1 in i64 (different mathematical values)
678        assert!(!apply_equal(&max_unsigned, &Value::Int(-1)));
679        // i64::MAX can be represented as u64, so should match
680        assert!(apply_equal(&Value::Uint(i64::MAX as u64), &max_signed));
681
682        // Test with empty collections
683        let empty_bytes = Value::Bytes(vec![]);
684        let empty_string = Value::String(String::new());
685
686        assert!(apply_equal(&empty_bytes, &empty_bytes));
687        assert!(apply_equal(&empty_string, &empty_string));
688        assert!(!apply_equal(&empty_bytes, &empty_string));
689    }
690
691    // Tests for apply_not_equal function
692    #[test]
693    fn test_apply_not_equal_uint_same_value() {
694        let left = Value::Uint(42);
695        let right = Value::Uint(42);
696        assert!(!apply_not_equal(&left, &right));
697    }
698
699    #[test]
700    fn test_apply_not_equal_uint_different_value() {
701        let left = Value::Uint(42);
702        let right = Value::Uint(24);
703        assert!(apply_not_equal(&left, &right));
704    }
705
706    #[test]
707    fn test_apply_not_equal_uint_zero() {
708        let left = Value::Uint(0);
709        let right = Value::Uint(0);
710        assert!(!apply_not_equal(&left, &right));
711    }
712
713    #[test]
714    fn test_apply_not_equal_uint_max_value() {
715        let left = Value::Uint(u64::MAX);
716        let right = Value::Uint(u64::MAX);
717        assert!(!apply_not_equal(&left, &right));
718
719        let left = Value::Uint(u64::MAX);
720        let right = Value::Uint(0);
721        assert!(apply_not_equal(&left, &right));
722    }
723
724    #[test]
725    fn test_apply_not_equal_int_same_value() {
726        let left = Value::Int(42);
727        let right = Value::Int(42);
728        assert!(!apply_not_equal(&left, &right));
729    }
730
731    #[test]
732    fn test_apply_not_equal_int_different_value() {
733        let left = Value::Int(42);
734        let right = Value::Int(-42);
735        assert!(apply_not_equal(&left, &right));
736    }
737
738    #[test]
739    fn test_apply_not_equal_int_negative() {
740        let left = Value::Int(-100);
741        let right = Value::Int(-100);
742        assert!(!apply_not_equal(&left, &right));
743
744        let left = Value::Int(-100);
745        let right = Value::Int(100);
746        assert!(apply_not_equal(&left, &right));
747    }
748
749    #[test]
750    fn test_apply_not_equal_int_zero() {
751        let left = Value::Int(0);
752        let right = Value::Int(0);
753        assert!(!apply_not_equal(&left, &right));
754    }
755
756    #[test]
757    fn test_apply_not_equal_int_extreme_values() {
758        let left = Value::Int(i64::MAX);
759        let right = Value::Int(i64::MAX);
760        assert!(!apply_not_equal(&left, &right));
761
762        let left = Value::Int(i64::MIN);
763        let right = Value::Int(i64::MIN);
764        assert!(!apply_not_equal(&left, &right));
765
766        let left = Value::Int(i64::MAX);
767        let right = Value::Int(i64::MIN);
768        assert!(apply_not_equal(&left, &right));
769    }
770
771    #[test]
772    fn test_apply_not_equal_bytes_same_value() {
773        let left = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
774        let right = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
775        assert!(!apply_not_equal(&left, &right));
776    }
777
778    #[test]
779    fn test_apply_not_equal_bytes_different_value() {
780        let left = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
781        let right = Value::Bytes(vec![0x50, 0x4b, 0x03, 0x04]);
782        assert!(apply_not_equal(&left, &right));
783    }
784
785    #[test]
786    fn test_apply_not_equal_bytes_empty() {
787        let left = Value::Bytes(vec![]);
788        let right = Value::Bytes(vec![]);
789        assert!(!apply_not_equal(&left, &right));
790    }
791
792    #[test]
793    fn test_apply_not_equal_bytes_different_length() {
794        let left = Value::Bytes(vec![0x7f, 0x45]);
795        let right = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
796        assert!(apply_not_equal(&left, &right));
797    }
798
799    #[test]
800    fn test_apply_not_equal_bytes_single_byte() {
801        let left = Value::Bytes(vec![0x7f]);
802        let right = Value::Bytes(vec![0x7f]);
803        assert!(!apply_not_equal(&left, &right));
804
805        let left = Value::Bytes(vec![0x7f]);
806        let right = Value::Bytes(vec![0x45]);
807        assert!(apply_not_equal(&left, &right));
808    }
809
810    #[test]
811    fn test_apply_not_equal_string_same_value() {
812        let left = Value::String("hello".to_string());
813        let right = Value::String("hello".to_string());
814        assert!(!apply_not_equal(&left, &right));
815    }
816
817    #[test]
818    fn test_apply_not_equal_string_different_value() {
819        let left = Value::String("hello".to_string());
820        let right = Value::String("world".to_string());
821        assert!(apply_not_equal(&left, &right));
822    }
823
824    #[test]
825    fn test_apply_not_equal_string_empty() {
826        let left = Value::String(String::new());
827        let right = Value::String(String::new());
828        assert!(!apply_not_equal(&left, &right));
829    }
830
831    #[test]
832    fn test_apply_not_equal_string_case_sensitive() {
833        let left = Value::String("Hello".to_string());
834        let right = Value::String("hello".to_string());
835        assert!(apply_not_equal(&left, &right));
836    }
837
838    #[test]
839    fn test_apply_not_equal_string_unicode() {
840        let left = Value::String("🦀 Rust".to_string());
841        let right = Value::String("🦀 Rust".to_string());
842        assert!(!apply_not_equal(&left, &right));
843
844        let left = Value::String("🦀 Rust".to_string());
845        let right = Value::String("🐍 Python".to_string());
846        assert!(apply_not_equal(&left, &right));
847    }
848
849    #[test]
850    fn test_apply_not_equal_string_whitespace() {
851        let left = Value::String("hello world".to_string());
852        let right = Value::String("hello world".to_string());
853        assert!(!apply_not_equal(&left, &right));
854
855        let left = Value::String("hello world".to_string());
856        let right = Value::String("hello  world".to_string()); // Extra space
857        assert!(apply_not_equal(&left, &right));
858    }
859
860    // Cross-type comparison tests for not_equal (should all return true)
861    #[test]
862    fn test_apply_not_equal_uint_vs_int() {
863        // Same numeric value across types should be equal (not not-equal)
864        let left = Value::Uint(42);
865        let right = Value::Int(42);
866        assert!(!apply_not_equal(&left, &right));
867
868        let left = Value::Uint(0);
869        let right = Value::Int(0);
870        assert!(!apply_not_equal(&left, &right));
871
872        // Different numeric values should be not-equal
873        let left = Value::Uint(42);
874        let right = Value::Int(-42);
875        assert!(apply_not_equal(&left, &right));
876    }
877
878    #[test]
879    fn test_apply_not_equal_uint_vs_bytes() {
880        let left = Value::Uint(42);
881        let right = Value::Bytes(vec![42]);
882        assert!(apply_not_equal(&left, &right));
883    }
884
885    #[test]
886    fn test_apply_not_equal_uint_vs_string() {
887        let left = Value::Uint(42);
888        let right = Value::String("42".to_string());
889        assert!(apply_not_equal(&left, &right));
890    }
891
892    #[test]
893    fn test_apply_not_equal_int_vs_bytes() {
894        let left = Value::Int(-42);
895        let right = Value::Bytes(vec![214]); // -42 as u8
896        assert!(apply_not_equal(&left, &right));
897    }
898
899    #[test]
900    fn test_apply_not_equal_int_vs_string() {
901        let left = Value::Int(-42);
902        let right = Value::String("-42".to_string());
903        assert!(apply_not_equal(&left, &right));
904    }
905
906    #[test]
907    fn test_apply_not_equal_bytes_vs_string() {
908        let left = Value::Bytes(vec![104, 101, 108, 108, 111]); // "hello" as bytes
909        let right = Value::String("hello".to_string());
910        assert!(apply_not_equal(&left, &right));
911    }
912
913    #[test]
914    fn test_apply_not_equal_all_cross_type_combinations() {
915        let values = [
916            Value::Uint(42),
917            Value::Int(42),
918            Value::Bytes(vec![42]),
919            Value::String("42".to_string()),
920        ];
921
922        // Test cross-type comparisons for not_equal
923        for (i, left) in values.iter().enumerate() {
924            for (j, right) in values.iter().enumerate() {
925                if i != j {
926                    let result = apply_not_equal(left, right);
927                    // Uint(42) and Int(42) should be equal, so not_equal is false
928                    if (i <= 1) && (j <= 1) {
929                        assert!(
930                            !result,
931                            "Integer cross-type not_equal should be false: {left:?} vs {right:?}"
932                        );
933                    } else {
934                        assert!(
935                            result,
936                            "Non-integer cross-type not_equal should be true: {left:?} vs {right:?}"
937                        );
938                    }
939                }
940            }
941        }
942    }
943
944    #[test]
945    fn test_apply_not_equal_consistency_with_equal() {
946        let test_cases = vec![
947            (Value::Uint(42), Value::Uint(42)),
948            (Value::Uint(42), Value::Uint(24)),
949            (Value::Int(-100), Value::Int(-100)),
950            (Value::Int(-100), Value::Int(100)),
951            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
952            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![3, 2, 1])),
953            (
954                Value::String("test".to_string()),
955                Value::String("test".to_string()),
956            ),
957            (
958                Value::String("test".to_string()),
959                Value::String("different".to_string()),
960            ),
961            // Cross-type cases
962            (Value::Uint(42), Value::Int(42)),
963            (Value::Uint(42), Value::String("42".to_string())),
964            (Value::Bytes(vec![42]), Value::Uint(42)),
965        ];
966
967        // Test that apply_not_equal is always the negation of apply_equal
968        for (left, right) in test_cases {
969            let equal_result = apply_equal(&left, &right);
970            let not_equal_result = apply_not_equal(&left, &right);
971            assert_eq!(
972                equal_result, !not_equal_result,
973                "apply_not_equal should be negation of apply_equal: {left:?} vs {right:?}"
974            );
975        }
976    }
977
978    #[test]
979    fn test_apply_not_equal_edge_cases() {
980        // Test with maximum values
981        let max_unsigned = Value::Uint(u64::MAX);
982        let max_signed = Value::Int(i64::MAX);
983        let min_int = Value::Int(i64::MIN);
984
985        assert!(!apply_not_equal(&max_unsigned, &max_unsigned));
986        assert!(!apply_not_equal(&max_signed, &max_signed));
987        assert!(!apply_not_equal(&min_int, &min_int));
988
989        // Test with empty collections
990        let empty_bytes = Value::Bytes(vec![]);
991        let empty_string = Value::String(String::new());
992
993        assert!(!apply_not_equal(&empty_bytes, &empty_bytes));
994        assert!(!apply_not_equal(&empty_string, &empty_string));
995        assert!(apply_not_equal(&empty_bytes, &empty_string));
996    }
997
998    #[test]
999    fn test_apply_not_equal_various_value_combinations() {
1000        // Test various combinations to ensure comprehensive coverage
1001        let test_cases = vec![
1002            // Uint variations
1003            (Value::Uint(0), Value::Uint(1), true),
1004            (Value::Uint(100), Value::Uint(100), false),
1005            (Value::Uint(u64::MAX), Value::Uint(u64::MAX - 1), true),
1006            // Int variations
1007            (Value::Int(0), Value::Int(-1), true),
1008            (Value::Int(-50), Value::Int(-50), false),
1009            (Value::Int(i64::MIN), Value::Int(i64::MAX), true),
1010            // Bytes variations
1011            (Value::Bytes(vec![0]), Value::Bytes(vec![1]), true),
1012            (
1013                Value::Bytes(vec![255, 254]),
1014                Value::Bytes(vec![255, 254]),
1015                false,
1016            ),
1017            (Value::Bytes(vec![]), Value::Bytes(vec![0]), true),
1018            // String variations
1019            (
1020                Value::String("a".to_string()),
1021                Value::String("b".to_string()),
1022                true,
1023            ),
1024            (
1025                Value::String("same".to_string()),
1026                Value::String("same".to_string()),
1027                false,
1028            ),
1029            (
1030                Value::String(String::new()),
1031                Value::String("non-empty".to_string()),
1032                true,
1033            ),
1034        ];
1035
1036        for (left, right, expected) in test_cases {
1037            assert_eq!(
1038                apply_not_equal(&left, &right),
1039                expected,
1040                "apply_not_equal({left:?}, {right:?}) should be {expected}"
1041            );
1042        }
1043    }
1044
1045    // Tests for apply_bitwise_and function
1046    #[test]
1047    fn test_apply_bitwise_and_uint_basic() {
1048        // Basic bit checking
1049        assert!(apply_bitwise_and(&Value::Uint(0x01), &Value::Uint(0x01))); // Bit 0 set
1050        assert!(!apply_bitwise_and(&Value::Uint(0x02), &Value::Uint(0x01))); // Bit 0 not set
1051        assert!(apply_bitwise_and(&Value::Uint(0x03), &Value::Uint(0x01))); // Bit 0 set among others
1052    }
1053
1054    #[test]
1055    fn test_apply_bitwise_and_uint_multiple_bits() {
1056        // Multiple bit patterns
1057        assert!(apply_bitwise_and(&Value::Uint(0xFF), &Value::Uint(0x0F))); // Any of lower 4 bits
1058        assert!(!apply_bitwise_and(&Value::Uint(0xF0), &Value::Uint(0x0F))); // None of lower 4 bits
1059        assert!(!apply_bitwise_and(&Value::Uint(0xAA), &Value::Uint(0x55))); // No overlap (0xAA = 10101010, 0x55 = 01010101)
1060        assert!(apply_bitwise_and(&Value::Uint(0xAA), &Value::Uint(0xAA))); // Same pattern
1061    }
1062
1063    #[test]
1064    fn test_apply_bitwise_and_uint_edge_cases() {
1065        // Zero cases
1066        assert!(!apply_bitwise_and(&Value::Uint(0), &Value::Uint(0xFF))); // Zero & anything = 0
1067        assert!(!apply_bitwise_and(&Value::Uint(0xFF), &Value::Uint(0))); // Anything & zero = 0
1068        assert!(!apply_bitwise_and(&Value::Uint(0), &Value::Uint(0))); // Zero & zero = 0
1069
1070        // Maximum values
1071        assert!(apply_bitwise_and(&Value::Uint(u64::MAX), &Value::Uint(1))); // Max & 1
1072        assert!(apply_bitwise_and(
1073            &Value::Uint(u64::MAX),
1074            &Value::Uint(u64::MAX)
1075        )); // Max & Max
1076    }
1077
1078    #[test]
1079    fn test_apply_bitwise_and_uint_specific_patterns() {
1080        // Common magic number patterns
1081        assert!(apply_bitwise_and(
1082            &Value::Uint(0x7F45_4C46),
1083            &Value::Uint(0xFF00_0000)
1084        )); // ELF magic high byte
1085        assert!(apply_bitwise_and(
1086            &Value::Uint(0x504B_0304),
1087            &Value::Uint(0xFFFF_0000)
1088        )); // ZIP magic high word
1089        assert!(!apply_bitwise_and(
1090            &Value::Uint(0x1234_5678),
1091            &Value::Uint(0x0000_0001)
1092        )); // Bit 0 not set
1093    }
1094
1095    #[test]
1096    fn test_apply_bitwise_and_int_basic() {
1097        // Basic signed integer bitwise AND
1098        assert!(apply_bitwise_and(&Value::Int(1), &Value::Int(1))); // Positive & positive
1099        assert!(!apply_bitwise_and(&Value::Int(2), &Value::Int(1))); // Different bits
1100        assert!(apply_bitwise_and(&Value::Int(3), &Value::Int(1))); // Multiple bits, one matches
1101    }
1102
1103    #[test]
1104    fn test_apply_bitwise_and_int_negative() {
1105        // Negative number bitwise AND (uses two's complement)
1106        assert!(apply_bitwise_and(&Value::Int(-1), &Value::Int(1))); // -1 has all bits set
1107        assert!(apply_bitwise_and(&Value::Int(-2), &Value::Int(2))); // -2 & 2 should have bit 1 set
1108        assert!(!apply_bitwise_and(&Value::Int(-2), &Value::Int(1))); // -2 & 1 should be 0 (bit 0 not set in -2)
1109    }
1110
1111    #[test]
1112    fn test_apply_bitwise_and_int_zero() {
1113        // Zero cases with signed integers
1114        assert!(!apply_bitwise_and(&Value::Int(0), &Value::Int(0xFF))); // Zero & anything = 0
1115        assert!(!apply_bitwise_and(&Value::Int(0xFF), &Value::Int(0))); // Anything & zero = 0
1116        assert!(!apply_bitwise_and(&Value::Int(0), &Value::Int(0))); // Zero & zero = 0
1117    }
1118
1119    #[test]
1120    fn test_apply_bitwise_and_int_extreme_values() {
1121        // Extreme signed integer values
1122        assert!(apply_bitwise_and(&Value::Int(i64::MAX), &Value::Int(1))); // Max positive & 1
1123        assert!(apply_bitwise_and(
1124            &Value::Int(i64::MIN),
1125            &Value::Int(i64::MIN)
1126        )); // Min & Min
1127        assert!(apply_bitwise_and(&Value::Int(i64::MIN), &Value::Int(-1))); // Min & -1 (all bits set)
1128    }
1129
1130    #[test]
1131    fn test_apply_bitwise_and_mixed_int_uint() {
1132        // Mixed signed/unsigned operations
1133        assert!(apply_bitwise_and(&Value::Uint(0xFF), &Value::Int(0x0F))); // Uint & Int
1134        assert!(apply_bitwise_and(&Value::Int(0xFF), &Value::Uint(0x0F))); // Int & Uint
1135        assert!(!apply_bitwise_and(&Value::Uint(0xF0), &Value::Int(0x0F))); // No overlap
1136        assert!(!apply_bitwise_and(&Value::Int(0xF0), &Value::Uint(0x0F))); // No overlap
1137    }
1138
1139    #[test]
1140    fn test_apply_bitwise_and_mixed_negative_uint() {
1141        // Negative int with uint (negative numbers have high bits set)
1142        assert!(apply_bitwise_and(&Value::Int(-1), &Value::Uint(1))); // -1 & 1
1143        assert!(apply_bitwise_and(&Value::Uint(1), &Value::Int(-1))); // 1 & -1
1144        assert!(!apply_bitwise_and(&Value::Int(-2), &Value::Uint(1))); // -2 & 1 (bit 0 not set in -2)
1145        assert!(!apply_bitwise_and(&Value::Uint(1), &Value::Int(-2))); // 1 & -2
1146    }
1147
1148    #[test]
1149    fn test_apply_bitwise_and_non_integer_types() {
1150        // Non-integer types should return false
1151        assert!(!apply_bitwise_and(
1152            &Value::String("test".to_string()),
1153            &Value::Uint(0x01)
1154        ));
1155        assert!(!apply_bitwise_and(
1156            &Value::Uint(0x01),
1157            &Value::String("test".to_string())
1158        ));
1159        assert!(!apply_bitwise_and(
1160            &Value::Bytes(vec![1]),
1161            &Value::Uint(0x01)
1162        ));
1163        assert!(!apply_bitwise_and(
1164            &Value::Uint(0x01),
1165            &Value::Bytes(vec![1])
1166        ));
1167        assert!(!apply_bitwise_and(
1168            &Value::String("a".to_string()),
1169            &Value::String("b".to_string())
1170        ));
1171        assert!(!apply_bitwise_and(
1172            &Value::Bytes(vec![1]),
1173            &Value::Bytes(vec![1])
1174        ));
1175    }
1176
1177    #[test]
1178    fn test_apply_bitwise_and_all_non_integer_combinations() {
1179        let non_integer_values = [Value::String("test".to_string()), Value::Bytes(vec![42])];
1180
1181        let integer_values = [Value::Uint(42), Value::Int(42)];
1182
1183        // Test all combinations of non-integer with integer
1184        for non_int in &non_integer_values {
1185            for int_val in &integer_values {
1186                assert!(
1187                    !apply_bitwise_and(non_int, int_val),
1188                    "Non-integer & integer should be false: {non_int:?} & {int_val:?}"
1189                );
1190                assert!(
1191                    !apply_bitwise_and(int_val, non_int),
1192                    "Integer & non-integer should be false: {int_val:?} & {non_int:?}"
1193                );
1194            }
1195        }
1196
1197        // Test all combinations of non-integer with non-integer
1198        for left in &non_integer_values {
1199            for right in &non_integer_values {
1200                assert!(
1201                    !apply_bitwise_and(left, right),
1202                    "Non-integer & non-integer should be false: {left:?} & {right:?}"
1203                );
1204            }
1205        }
1206    }
1207
1208    #[test]
1209    fn test_apply_bitwise_and_bit_patterns() {
1210        // Test specific bit patterns commonly used in magic rules
1211        let test_cases = vec![
1212            // (value, mask, expected)
1213            (0b0000_0001_u64, 0b0000_0001_u64, true), // Bit 0 set
1214            (0b0000_0010_u64, 0b0000_0001_u64, false), // Bit 0 not set
1215            (0b0000_0011_u64, 0b0000_0001_u64, true), // Bit 0 set among others
1216            (0b1111_1111_u64, 0b0000_1111_u64, true), // Any of lower 4 bits
1217            (0b1111_0000_u64, 0b0000_1111_u64, false), // None of lower 4 bits
1218            (0b1010_1010_u64, 0b0101_0101_u64, false), // No overlap
1219            (0b1010_1010_u64, 0b1010_1010_u64, true), // Perfect match
1220            (0b1111_1111_u64, 0b0000_0000_u64, false), // Mask is zero
1221            (0b0000_0000_u64, 0b1111_1111_u64, false), // Value is zero
1222        ];
1223
1224        for (value, mask, expected) in test_cases {
1225            assert_eq!(
1226                apply_bitwise_and(&Value::Uint(value), &Value::Uint(mask)),
1227                expected,
1228                "apply_bitwise_and(0b{value:08b}, 0b{mask:08b}) should be {expected}"
1229            );
1230        }
1231    }
1232
1233    #[test]
1234    fn test_apply_bitwise_and_magic_file_patterns() {
1235        // Test patterns commonly found in magic files
1236
1237        // ELF magic number (0x7F454C46) - check if it's an ELF file
1238        let elf_magic = Value::Uint(0x7F45_4C46);
1239        let elf_mask = Value::Uint(0xFFFF_FFFF);
1240        assert!(apply_bitwise_and(&elf_magic, &elf_mask));
1241
1242        // Check specific bytes in ELF magic
1243        assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x7F00_0000))); // First byte
1244        assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x0045_0000))); // Second byte 'E'
1245        assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x0000_4C00))); // Third byte 'L'
1246        assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x0000_0046))); // Fourth byte 'F'
1247
1248        // ZIP magic number (0x504B0304) - check if it's a ZIP file
1249        let zip_magic = Value::Uint(0x504B_0304);
1250        assert!(apply_bitwise_and(&zip_magic, &Value::Uint(0x504B_0000))); // PK signature
1251        assert!(!apply_bitwise_and(&zip_magic, &Value::Uint(0x0000_0001))); // Bit 0 not set
1252
1253        // PDF magic (%PDF) - first few bytes
1254        let pdf_magic = Value::Uint(0x2550_4446); // "%PDF" as uint32
1255        assert!(apply_bitwise_and(&pdf_magic, &Value::Uint(0xFF00_0000))); // '%' character
1256        assert!(apply_bitwise_and(&pdf_magic, &Value::Uint(0x00FF_0000))); // 'P' character
1257    }
1258
1259    #[test]
1260    fn test_apply_bitwise_and_symmetry() {
1261        // Test that bitwise AND is commutative for integer types
1262        let test_cases = vec![
1263            (Value::Uint(0xFF), Value::Uint(0x0F)),
1264            (Value::Int(42), Value::Int(24)),
1265            (Value::Uint(0xAAAA), Value::Int(0x5555)),
1266            (Value::Int(-1), Value::Uint(1)),
1267        ];
1268
1269        for (left, right) in test_cases {
1270            let left_to_right = apply_bitwise_and(&left, &right);
1271            let right_to_left = apply_bitwise_and(&right, &left);
1272            assert_eq!(
1273                left_to_right, right_to_left,
1274                "Bitwise AND should be commutative: {left:?} & {right:?}"
1275            );
1276        }
1277    }
1278
1279    #[test]
1280    fn test_apply_bitwise_and_associativity_concept() {
1281        // While we can't test true associativity with binary function,
1282        // we can test that the operation behaves consistently
1283        let value = Value::Uint(0b1111_0000);
1284        let mask1 = Value::Uint(0b1100_0000);
1285        let mask2 = Value::Uint(0b0011_0000);
1286        let combined_mask = Value::Uint(0b1111_0000);
1287
1288        // (value & mask1) should be true if any bits match
1289        assert!(apply_bitwise_and(&value, &mask1));
1290        assert!(apply_bitwise_and(&value, &mask2));
1291        assert!(apply_bitwise_and(&value, &combined_mask));
1292    }
1293
1294    // Tests for apply_operator function
1295    #[test]
1296    fn test_apply_operator_equal() {
1297        // Test Equal operator dispatch
1298        assert!(apply_operator(
1299            &Operator::Equal,
1300            &Value::Uint(42),
1301            &Value::Uint(42)
1302        ));
1303        assert!(!apply_operator(
1304            &Operator::Equal,
1305            &Value::Uint(42),
1306            &Value::Uint(24)
1307        ));
1308
1309        // Test with different value types
1310        assert!(apply_operator(
1311            &Operator::Equal,
1312            &Value::String("hello".to_string()),
1313            &Value::String("hello".to_string())
1314        ));
1315        assert!(!apply_operator(
1316            &Operator::Equal,
1317            &Value::String("hello".to_string()),
1318            &Value::String("world".to_string())
1319        ));
1320
1321        // Cross-type integer coercion
1322        assert!(apply_operator(
1323            &Operator::Equal,
1324            &Value::Uint(42),
1325            &Value::Int(42)
1326        ));
1327    }
1328
1329    #[test]
1330    fn test_apply_operator_not_equal() {
1331        // Test NotEqual operator dispatch
1332        assert!(!apply_operator(
1333            &Operator::NotEqual,
1334            &Value::Uint(42),
1335            &Value::Uint(42)
1336        ));
1337        assert!(apply_operator(
1338            &Operator::NotEqual,
1339            &Value::Uint(42),
1340            &Value::Uint(24)
1341        ));
1342
1343        // Test with different value types
1344        assert!(!apply_operator(
1345            &Operator::NotEqual,
1346            &Value::String("hello".to_string()),
1347            &Value::String("hello".to_string())
1348        ));
1349        assert!(apply_operator(
1350            &Operator::NotEqual,
1351            &Value::String("hello".to_string()),
1352            &Value::String("world".to_string())
1353        ));
1354
1355        // Cross-type integer coercion: same value, so not-equal is false
1356        assert!(!apply_operator(
1357            &Operator::NotEqual,
1358            &Value::Uint(42),
1359            &Value::Int(42)
1360        ));
1361    }
1362
1363    #[test]
1364    fn test_apply_operator_bitwise_and() {
1365        // Test BitwiseAnd operator dispatch
1366        assert!(apply_operator(
1367            &Operator::BitwiseAnd,
1368            &Value::Uint(0xFF),
1369            &Value::Uint(0x0F)
1370        ));
1371        assert!(!apply_operator(
1372            &Operator::BitwiseAnd,
1373            &Value::Uint(0xF0),
1374            &Value::Uint(0x0F)
1375        ));
1376
1377        // Test with signed integers
1378        assert!(apply_operator(
1379            &Operator::BitwiseAnd,
1380            &Value::Int(-1),
1381            &Value::Int(1)
1382        ));
1383        assert!(!apply_operator(
1384            &Operator::BitwiseAnd,
1385            &Value::Int(-2),
1386            &Value::Int(1)
1387        ));
1388
1389        // Test with mixed types
1390        assert!(apply_operator(
1391            &Operator::BitwiseAnd,
1392            &Value::Uint(0xFF),
1393            &Value::Int(0x0F)
1394        ));
1395
1396        // Non-integer types should return false
1397        assert!(!apply_operator(
1398            &Operator::BitwiseAnd,
1399            &Value::String("test".to_string()),
1400            &Value::Uint(0x01)
1401        ));
1402    }
1403
1404    #[test]
1405    fn test_apply_operator_all_operators_with_same_values() {
1406        let test_cases = vec![
1407            // Same values - Equal should be true, NotEqual false, BitwiseAnd depends on value
1408            (Value::Uint(42), Value::Uint(42)),
1409            (Value::Int(-100), Value::Int(-100)),
1410            (
1411                Value::String("test".to_string()),
1412                Value::String("test".to_string()),
1413            ),
1414            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
1415        ];
1416
1417        for (left, right) in test_cases {
1418            // Equal should always be true for same values
1419            assert!(
1420                apply_operator(&Operator::Equal, &left, &right),
1421                "Equal should be true for same values: {left:?} == {right:?}"
1422            );
1423
1424            // NotEqual should always be false for same values
1425            assert!(
1426                !apply_operator(&Operator::NotEqual, &left, &right),
1427                "NotEqual should be false for same values: {left:?} != {right:?}"
1428            );
1429
1430            // BitwiseAnd behavior depends on the value type and content
1431            let bitwise_result = apply_operator(&Operator::BitwiseAnd, &left, &right);
1432            match &left {
1433                Value::Uint(n) => {
1434                    // For unsigned integers, BitwiseAnd should be true if value is non-zero
1435                    let expected = *n != 0;
1436                    assert_eq!(
1437                        bitwise_result, expected,
1438                        "BitwiseAnd for Uint({n}) should be {expected}"
1439                    );
1440                }
1441                Value::Int(n) => {
1442                    // For signed integers, BitwiseAnd should be true if value is non-zero
1443                    let expected = *n != 0;
1444                    assert_eq!(
1445                        bitwise_result, expected,
1446                        "BitwiseAnd for Int({n}) should be {expected}"
1447                    );
1448                }
1449                _ => {
1450                    // For non-integers, BitwiseAnd should always be false
1451                    assert!(
1452                        !bitwise_result,
1453                        "BitwiseAnd should be false for non-integer types: {left:?}"
1454                    );
1455                }
1456            }
1457        }
1458    }
1459
1460    #[test]
1461    fn test_apply_operator_all_operators_with_different_values() {
1462        let test_cases = vec![
1463            // Different values of same type
1464            (Value::Uint(42), Value::Uint(24)),
1465            (Value::Int(100), Value::Int(-100)),
1466            (
1467                Value::String("hello".to_string()),
1468                Value::String("world".to_string()),
1469            ),
1470            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![4, 5, 6])),
1471            // Different types (non-coercible)
1472            (Value::Uint(42), Value::String("42".to_string())),
1473            (Value::Int(42), Value::Bytes(vec![42])),
1474        ];
1475
1476        for (left, right) in test_cases {
1477            // Equal should always be false for truly different values
1478            assert!(
1479                !apply_operator(&Operator::Equal, &left, &right),
1480                "Equal should be false for different values: {left:?} == {right:?}"
1481            );
1482
1483            // NotEqual should always be true for truly different values
1484            assert!(
1485                apply_operator(&Operator::NotEqual, &left, &right),
1486                "NotEqual should be true for different values: {left:?} != {right:?}"
1487            );
1488
1489            // BitwiseAnd behavior depends on the value types and content
1490            let bitwise_result = apply_operator(&Operator::BitwiseAnd, &left, &right);
1491            match (&left, &right) {
1492                (Value::Uint(a), Value::Uint(b)) => {
1493                    let expected = (a & b) != 0;
1494                    assert_eq!(
1495                        bitwise_result, expected,
1496                        "BitwiseAnd for Uint({a}) & Uint({b}) should be {expected}"
1497                    );
1498                }
1499                (Value::Int(a), Value::Int(b)) => {
1500                    #[allow(clippy::cast_sign_loss)]
1501                    let expected = ((*a as u64) & (*b as u64)) != 0;
1502                    assert_eq!(
1503                        bitwise_result, expected,
1504                        "BitwiseAnd for Int({a}) & Int({b}) should be {expected}"
1505                    );
1506                }
1507                (Value::Uint(a), Value::Int(b)) | (Value::Int(b), Value::Uint(a)) => {
1508                    #[allow(clippy::cast_sign_loss)]
1509                    let expected = (a & (*b as u64)) != 0;
1510                    assert_eq!(
1511                        bitwise_result, expected,
1512                        "BitwiseAnd for mixed Uint/Int should be {expected}"
1513                    );
1514                }
1515                _ => {
1516                    // For non-integer types, BitwiseAnd should always be false
1517                    assert!(
1518                        !bitwise_result,
1519                        "BitwiseAnd should be false for non-integer types: {left:?} & {right:?}"
1520                    );
1521                }
1522            }
1523        }
1524    }
1525
1526    #[test]
1527    fn test_apply_operator_consistency_with_individual_functions() {
1528        let test_cases = vec![
1529            (Value::Uint(42), Value::Uint(42)),
1530            (Value::Uint(42), Value::Uint(24)),
1531            (Value::Int(-100), Value::Int(-100)),
1532            (Value::Int(100), Value::Int(-100)),
1533            (
1534                Value::String("test".to_string()),
1535                Value::String("test".to_string()),
1536            ),
1537            (
1538                Value::String("hello".to_string()),
1539                Value::String("world".to_string()),
1540            ),
1541            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![1, 2, 3])),
1542            (Value::Bytes(vec![1, 2, 3]), Value::Bytes(vec![4, 5, 6])),
1543            // Cross-type cases
1544            (Value::Uint(42), Value::Int(42)),
1545            (Value::Uint(42), Value::String("42".to_string())),
1546            (Value::Int(42), Value::Bytes(vec![42])),
1547        ];
1548
1549        for (left, right) in test_cases {
1550            // Test that apply_operator gives same results as individual functions
1551            assert_eq!(
1552                apply_operator(&Operator::Equal, &left, &right),
1553                apply_equal(&left, &right),
1554                "apply_operator(Equal) should match apply_equal for {left:?}, {right:?}"
1555            );
1556
1557            assert_eq!(
1558                apply_operator(&Operator::NotEqual, &left, &right),
1559                apply_not_equal(&left, &right),
1560                "apply_operator(NotEqual) should match apply_not_equal for {left:?}, {right:?}"
1561            );
1562
1563            assert_eq!(
1564                apply_operator(&Operator::BitwiseAnd, &left, &right),
1565                apply_bitwise_and(&left, &right),
1566                "apply_operator(BitwiseAnd) should match apply_bitwise_and for {left:?}, {right:?}"
1567            );
1568        }
1569    }
1570
1571    #[test]
1572    fn test_apply_operator_magic_rule_scenarios() {
1573        // Test scenarios that would commonly appear in magic rules
1574
1575        // ELF magic number check
1576        let elf_magic = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
1577        let elf_expected = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
1578        assert!(apply_operator(&Operator::Equal, &elf_magic, &elf_expected));
1579        assert!(!apply_operator(
1580            &Operator::NotEqual,
1581            &elf_magic,
1582            &elf_expected
1583        ));
1584
1585        // ZIP magic number check
1586        let zip_magic = Value::Uint(0x504B_0304);
1587        let zip_expected = Value::Uint(0x504B_0304);
1588        assert!(apply_operator(&Operator::Equal, &zip_magic, &zip_expected));
1589
1590        // Bit flag checking (common in binary formats)
1591        let flags = Value::Uint(0b1101_0110);
1592        let flag_mask = Value::Uint(0b0000_0010); // Check if bit 1 is set
1593        assert!(apply_operator(&Operator::BitwiseAnd, &flags, &flag_mask));
1594
1595        let no_flag_mask = Value::Uint(0b0000_0001); // Check if bit 0 is set
1596        assert!(!apply_operator(
1597            &Operator::BitwiseAnd,
1598            &flags,
1599            &no_flag_mask
1600        ));
1601
1602        // String matching for text-based formats
1603        let content = Value::String("#!/bin/bash".to_string());
1604        let shebang = Value::String("#!/bin/bash".to_string());
1605        assert!(apply_operator(&Operator::Equal, &content, &shebang));
1606
1607        let not_shebang = Value::String("#!/usr/bin/python".to_string());
1608        assert!(apply_operator(&Operator::NotEqual, &content, &not_shebang));
1609
1610        // Version number checking
1611        let version = Value::Uint(2);
1612        let expected_version = Value::Uint(2);
1613        let old_version = Value::Uint(1);
1614        assert!(apply_operator(
1615            &Operator::Equal,
1616            &version,
1617            &expected_version
1618        ));
1619        assert!(apply_operator(&Operator::NotEqual, &version, &old_version));
1620    }
1621
1622    #[test]
1623    fn test_apply_operator_edge_cases() {
1624        // Test with extreme values
1625        let max_uint = Value::Uint(u64::MAX);
1626        let min_signed = Value::Int(i64::MIN);
1627        let max_signed = Value::Int(i64::MAX);
1628
1629        // Self-comparison should work
1630        assert!(apply_operator(&Operator::Equal, &max_uint, &max_uint));
1631        assert!(apply_operator(&Operator::Equal, &min_signed, &min_signed));
1632        assert!(apply_operator(&Operator::Equal, &max_signed, &max_signed));
1633
1634        // Cross-extreme comparisons
1635        assert!(apply_operator(&Operator::NotEqual, &max_uint, &min_signed));
1636        assert!(apply_operator(
1637            &Operator::NotEqual,
1638            &max_signed,
1639            &min_signed
1640        ));
1641
1642        // Bitwise operations with extreme values
1643        assert!(apply_operator(
1644            &Operator::BitwiseAnd,
1645            &max_uint,
1646            &Value::Uint(1)
1647        ));
1648        assert!(apply_operator(
1649            &Operator::BitwiseAnd,
1650            &min_signed,
1651            &min_signed
1652        ));
1653
1654        // Empty collections
1655        let empty_bytes = Value::Bytes(vec![]);
1656        let empty_string = Value::String(String::new());
1657        assert!(apply_operator(&Operator::Equal, &empty_bytes, &empty_bytes));
1658        assert!(apply_operator(
1659            &Operator::Equal,
1660            &empty_string,
1661            &empty_string
1662        ));
1663        assert!(apply_operator(
1664            &Operator::NotEqual,
1665            &empty_bytes,
1666            &empty_string
1667        ));
1668
1669        // Zero values
1670        let zero_uint = Value::Uint(0);
1671        let zero_signed = Value::Int(0);
1672        assert!(!apply_operator(
1673            &Operator::BitwiseAnd,
1674            &zero_uint,
1675            &Value::Uint(0xFF)
1676        ));
1677        assert!(!apply_operator(
1678            &Operator::BitwiseAnd,
1679            &zero_signed,
1680            &Value::Int(0xFF)
1681        ));
1682        assert!(!apply_operator(
1683            &Operator::NotEqual,
1684            &zero_uint,
1685            &zero_signed
1686        )); // Cross-type integer coercion: 0 == 0
1687    }
1688
1689    #[test]
1690    fn test_apply_operator_all_combinations() {
1691        let operators = [
1692            Operator::Equal,
1693            Operator::NotEqual,
1694            Operator::LessThan,
1695            Operator::GreaterThan,
1696            Operator::LessEqual,
1697            Operator::GreaterEqual,
1698            Operator::BitwiseAnd,
1699            Operator::BitwiseAndMask(0xFF),
1700        ];
1701        let values = [
1702            Value::Uint(42),
1703            Value::Int(-42),
1704            Value::Bytes(vec![42]),
1705            Value::String("42".to_string()),
1706        ];
1707
1708        // Test all operator-value combinations to ensure no panics
1709        for operator in &operators {
1710            for left in &values {
1711                for right in &values {
1712                    // This should not panic for any combination
1713                    let result = apply_operator(operator, left, right);
1714
1715                    // Verify the result is consistent with individual function calls
1716                    let expected = match operator {
1717                        Operator::Equal => apply_equal(left, right),
1718                        Operator::NotEqual => apply_not_equal(left, right),
1719                        Operator::LessThan => apply_less_than(left, right),
1720                        Operator::GreaterThan => apply_greater_than(left, right),
1721                        Operator::LessEqual => apply_less_equal(left, right),
1722                        Operator::GreaterEqual => apply_greater_equal(left, right),
1723                        Operator::BitwiseAnd => apply_bitwise_and(left, right),
1724                        Operator::BitwiseAndMask(mask) => {
1725                            // Apply mask to left value, then compare with right
1726                            let masked_left = match left {
1727                                Value::Uint(val) => Value::Uint(val & mask),
1728                                Value::Int(val) => {
1729                                    let i64_mask = if i64::try_from(*mask).is_ok() {
1730                                        i64::try_from(*mask).unwrap_or(0)
1731                                    } else {
1732                                        i64::from_ne_bytes(mask.to_ne_bytes())
1733                                    };
1734                                    Value::Int(val & i64_mask)
1735                                }
1736                                _ => return, // Skip non-numeric values in test
1737                            };
1738                            apply_equal(&masked_left, right)
1739                        }
1740                    };
1741
1742                    assert_eq!(
1743                        result, expected,
1744                        "apply_operator({operator:?}, {left:?}, {right:?}) should match individual function"
1745                    );
1746                }
1747            }
1748        }
1749    }
1750
1751    // ---- compare_values + comparison operator tests ----
1752
1753    #[test]
1754    fn test_compare_values_ordering() {
1755        use std::cmp::Ordering::*;
1756
1757        // Same-type integer comparisons
1758        assert_eq!(
1759            compare_values(&Value::Uint(5), &Value::Uint(10)),
1760            Some(Less)
1761        );
1762        assert_eq!(
1763            compare_values(&Value::Uint(10), &Value::Uint(10)),
1764            Some(Equal)
1765        );
1766        assert_eq!(
1767            compare_values(&Value::Uint(10), &Value::Uint(5)),
1768            Some(Greater)
1769        );
1770        assert_eq!(
1771            compare_values(&Value::Int(-10), &Value::Int(-5)),
1772            Some(Less)
1773        );
1774        assert_eq!(
1775            compare_values(&Value::Int(i64::MIN), &Value::Int(0)),
1776            Some(Less)
1777        );
1778
1779        // Cross-type integer comparisons via i128
1780        assert_eq!(compare_values(&Value::Int(-1), &Value::Uint(0)), Some(Less));
1781        assert_eq!(
1782            compare_values(&Value::Uint(42), &Value::Int(42)),
1783            Some(Equal)
1784        );
1785        assert_eq!(
1786            compare_values(&Value::Uint(u64::MAX), &Value::Int(-1)),
1787            Some(Greater)
1788        );
1789
1790        // String comparisons
1791        assert_eq!(
1792            compare_values(&Value::String("abc".into()), &Value::String("abd".into())),
1793            Some(Less)
1794        );
1795        assert_eq!(
1796            compare_values(&Value::String("abc".into()), &Value::String("abc".into())),
1797            Some(Equal)
1798        );
1799
1800        // Bytes comparisons (lexicographic, including different lengths)
1801        assert_eq!(
1802            compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![2])),
1803            Some(Less)
1804        );
1805        assert_eq!(
1806            compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![1])),
1807            Some(Equal)
1808        );
1809        assert_eq!(
1810            compare_values(&Value::Bytes(vec![1]), &Value::Bytes(vec![1, 2])),
1811            Some(Less)
1812        );
1813        assert_eq!(
1814            compare_values(&Value::Bytes(vec![]), &Value::Bytes(vec![1])),
1815            Some(Less)
1816        );
1817
1818        // Incomparable types return None
1819        assert_eq!(
1820            compare_values(&Value::Uint(1), &Value::String("1".into())),
1821            None
1822        );
1823        assert_eq!(compare_values(&Value::Int(1), &Value::Bytes(vec![1])), None);
1824    }
1825
1826    #[test]
1827    fn test_comparison_operators_consistency() {
1828        // Verify all four comparison functions agree with compare_values
1829        let pairs = vec![
1830            (Value::Uint(5), Value::Uint(10)),
1831            (Value::Uint(10), Value::Uint(10)),
1832            (Value::Uint(10), Value::Uint(5)),
1833            (Value::Int(-10), Value::Int(-5)),
1834            (Value::Int(-1), Value::Uint(0)),
1835            (Value::Uint(u64::MAX), Value::Int(-1)),
1836            (Value::String("abc".into()), Value::String("abd".into())),
1837            (Value::Bytes(vec![1, 2]), Value::Bytes(vec![1, 3])),
1838            (Value::Bytes(vec![1]), Value::Bytes(vec![1, 2])),
1839            (Value::Uint(1), Value::String("1".into())), // incomparable
1840        ];
1841
1842        for (left, right) in &pairs {
1843            let ord = compare_values(left, right);
1844            assert_eq!(
1845                apply_less_than(left, right),
1846                ord == Some(Ordering::Less),
1847                "< for {left:?}, {right:?}"
1848            );
1849            assert_eq!(
1850                apply_greater_than(left, right),
1851                ord == Some(Ordering::Greater),
1852                "> for {left:?}, {right:?}"
1853            );
1854            assert_eq!(
1855                apply_less_equal(left, right),
1856                matches!(ord, Some(Ordering::Less | Ordering::Equal)),
1857                "<= for {left:?}, {right:?}"
1858            );
1859            assert_eq!(
1860                apply_greater_equal(left, right),
1861                matches!(ord, Some(Ordering::Greater | Ordering::Equal)),
1862                ">= for {left:?}, {right:?}"
1863            );
1864        }
1865    }
1866}