Skip to main content

libmagic_rs/parser/
ast.rs

1// Copyright (c) 2025-2026 the libmagic-rs contributors
2// SPDX-License-Identifier: Apache-2.0
3
4//! Abstract Syntax Tree definitions for magic rules
5//!
6//! This module contains the core data structures that represent parsed magic rules
7//! and their components, including offset specifications, type kinds, operators, and values.
8
9use serde::{Deserialize, Serialize};
10
11/// Offset specification for locating data in files
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
13pub enum OffsetSpec {
14    /// Absolute offset from file start (or from file end if negative)
15    ///
16    /// Positive values are offsets from the start of the file.
17    /// Negative values are offsets from the end of the file (same as `FromEnd`).
18    ///
19    /// # Examples
20    ///
21    /// ```
22    /// use libmagic_rs::parser::ast::OffsetSpec;
23    ///
24    /// let offset = OffsetSpec::Absolute(0x10); // Read at byte 16 from start
25    /// let from_end = OffsetSpec::Absolute(-4); // 4 bytes before end of file
26    /// ```
27    Absolute(i64),
28
29    /// Indirect offset through pointer dereferencing
30    ///
31    /// Reads a pointer value at `base_offset`, interprets it according to `pointer_type`
32    /// and `endian`, then adds `adjustment` to get the final offset.
33    ///
34    /// # Examples
35    ///
36    /// ```
37    /// use libmagic_rs::parser::ast::{OffsetSpec, TypeKind, Endianness};
38    ///
39    /// let indirect = OffsetSpec::Indirect {
40    ///     base_offset: 0x20,
41    ///     pointer_type: TypeKind::Long { endian: Endianness::Little, signed: false },
42    ///     adjustment: 4,
43    ///     endian: Endianness::Little,
44    /// };
45    /// ```
46    Indirect {
47        /// Base offset to read pointer from
48        base_offset: i64,
49        /// Type of pointer value
50        pointer_type: TypeKind,
51        /// Adjustment to add to pointer value
52        adjustment: i64,
53        /// Endianness for pointer reading
54        endian: Endianness,
55    },
56
57    /// Relative offset from previous match position
58    ///
59    /// # Examples
60    ///
61    /// ```
62    /// use libmagic_rs::parser::ast::OffsetSpec;
63    ///
64    /// let relative = OffsetSpec::Relative(8); // 8 bytes after previous match
65    /// ```
66    Relative(i64),
67
68    /// Offset from end of file (negative values move towards start)
69    ///
70    /// # Examples
71    ///
72    /// ```
73    /// use libmagic_rs::parser::ast::OffsetSpec;
74    ///
75    /// let from_end = OffsetSpec::FromEnd(-16); // 16 bytes before end of file
76    /// ```
77    FromEnd(i64),
78}
79
80/// Data type specifications for interpreting bytes
81#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
82pub enum TypeKind {
83    /// Single byte
84    Byte {
85        /// Whether value is signed
86        signed: bool,
87    },
88    /// 16-bit integer
89    Short {
90        /// Byte order
91        endian: Endianness,
92        /// Whether value is signed
93        signed: bool,
94    },
95    /// 32-bit integer
96    Long {
97        /// Byte order
98        endian: Endianness,
99        /// Whether value is signed
100        signed: bool,
101    },
102    /// 64-bit integer
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use libmagic_rs::parser::ast::{TypeKind, Endianness};
108    ///
109    /// let quad = TypeKind::Quad { endian: Endianness::Big, signed: true };
110    /// assert_eq!(quad, TypeKind::Quad { endian: Endianness::Big, signed: true });
111    /// ```
112    Quad {
113        /// Byte order
114        endian: Endianness,
115        /// Whether value is signed
116        signed: bool,
117    },
118    /// String data
119    String {
120        /// Maximum length to read
121        max_length: Option<usize>,
122    },
123}
124
125impl TypeKind {
126    /// Returns the bit width of integer types, or `None` for non-integer types (e.g., String).
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// use libmagic_rs::parser::ast::{TypeKind, Endianness};
132    ///
133    /// assert_eq!(TypeKind::Byte { signed: false }.bit_width(), Some(8));
134    /// assert_eq!(TypeKind::Short { endian: Endianness::Native, signed: true }.bit_width(), Some(16));
135    /// assert_eq!(TypeKind::Long { endian: Endianness::Native, signed: true }.bit_width(), Some(32));
136    /// assert_eq!(TypeKind::Quad { endian: Endianness::Native, signed: true }.bit_width(), Some(64));
137    /// assert_eq!(TypeKind::String { max_length: None }.bit_width(), None);
138    /// ```
139    #[must_use]
140    pub const fn bit_width(&self) -> Option<u32> {
141        match self {
142            Self::Byte { .. } => Some(8),
143            Self::Short { .. } => Some(16),
144            Self::Long { .. } => Some(32),
145            Self::Quad { .. } => Some(64),
146            Self::String { .. } => None,
147        }
148    }
149}
150
151/// Comparison and bitwise operators
152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
153pub enum Operator {
154    /// Equality comparison (`=` or `==`)
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use libmagic_rs::parser::ast::Operator;
160    ///
161    /// let op = Operator::Equal;
162    /// assert_eq!(op, Operator::Equal);
163    /// ```
164    Equal,
165    /// Inequality comparison (`!=` or `<>`)
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// use libmagic_rs::parser::ast::Operator;
171    ///
172    /// let op = Operator::NotEqual;
173    /// assert_eq!(op, Operator::NotEqual);
174    /// ```
175    NotEqual,
176    /// Less-than comparison (`<`)
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// use libmagic_rs::parser::ast::Operator;
182    ///
183    /// let op = Operator::LessThan;
184    /// assert_eq!(op, Operator::LessThan);
185    /// ```
186    LessThan,
187    /// Greater-than comparison (`>`)
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// use libmagic_rs::parser::ast::Operator;
193    ///
194    /// let op = Operator::GreaterThan;
195    /// assert_eq!(op, Operator::GreaterThan);
196    /// ```
197    GreaterThan,
198    /// Less-than-or-equal comparison (`<=`)
199    ///
200    /// # Examples
201    ///
202    /// ```
203    /// use libmagic_rs::parser::ast::Operator;
204    ///
205    /// let op = Operator::LessEqual;
206    /// assert_eq!(op, Operator::LessEqual);
207    /// ```
208    LessEqual,
209    /// Greater-than-or-equal comparison (`>=`)
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use libmagic_rs::parser::ast::Operator;
215    ///
216    /// let op = Operator::GreaterEqual;
217    /// assert_eq!(op, Operator::GreaterEqual);
218    /// ```
219    GreaterEqual,
220    /// Bitwise AND operation without mask (`&`)
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// use libmagic_rs::parser::ast::Operator;
226    ///
227    /// let op = Operator::BitwiseAnd;
228    /// assert_eq!(op, Operator::BitwiseAnd);
229    /// ```
230    BitwiseAnd,
231    /// Bitwise AND operation with mask value (`&` with a mask operand)
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// use libmagic_rs::parser::ast::Operator;
237    ///
238    /// let op = Operator::BitwiseAndMask(0xFF00);
239    /// assert_eq!(op, Operator::BitwiseAndMask(0xFF00));
240    /// ```
241    BitwiseAndMask(u64),
242    /// Bitwise XOR operation (`^`)
243    ///
244    /// # Examples
245    ///
246    /// ```
247    /// use libmagic_rs::parser::ast::Operator;
248    ///
249    /// let op = Operator::BitwiseXor;
250    /// assert_eq!(op, Operator::BitwiseXor);
251    /// ```
252    BitwiseXor,
253    /// Bitwise NOT/complement operation (`~`)
254    ///
255    /// # Examples
256    ///
257    /// ```
258    /// use libmagic_rs::parser::ast::Operator;
259    ///
260    /// let op = Operator::BitwiseNot;
261    /// assert_eq!(op, Operator::BitwiseNot);
262    /// ```
263    BitwiseNot,
264    /// Match any value; condition always succeeds (`x`)
265    ///
266    /// # Examples
267    ///
268    /// ```
269    /// use libmagic_rs::parser::ast::Operator;
270    ///
271    /// let op = Operator::AnyValue;
272    /// assert_eq!(op, Operator::AnyValue);
273    /// ```
274    AnyValue,
275}
276
277/// Value types for rule matching
278#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
279pub enum Value {
280    /// Unsigned integer value
281    Uint(u64),
282    /// Signed integer value
283    Int(i64),
284    /// Byte sequence
285    Bytes(Vec<u8>),
286    /// String value
287    String(String),
288}
289
290/// Endianness specification for multi-byte values
291#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
292pub enum Endianness {
293    /// Little-endian byte order (least significant byte first)
294    Little,
295    /// Big-endian byte order (most significant byte first)
296    Big,
297    /// Native system byte order (matches target architecture)
298    Native,
299}
300
301/// Strength modifier for magic rules
302///
303/// Strength modifiers adjust the default strength calculation for a rule.
304/// They are specified using the `!:strength` directive in magic files.
305///
306/// # Examples
307///
308/// ```
309/// use libmagic_rs::parser::ast::StrengthModifier;
310///
311/// let add = StrengthModifier::Add(10);      // !:strength +10
312/// let sub = StrengthModifier::Subtract(5);  // !:strength -5
313/// let mul = StrengthModifier::Multiply(2);  // !:strength *2
314/// let div = StrengthModifier::Divide(2);    // !:strength /2
315/// let set = StrengthModifier::Set(50);      // !:strength =50
316/// ```
317#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
318pub enum StrengthModifier {
319    /// Add to the default strength: `!:strength +N`
320    Add(i32),
321    /// Subtract from the default strength: `!:strength -N`
322    Subtract(i32),
323    /// Multiply the default strength: `!:strength *N`
324    Multiply(i32),
325    /// Divide the default strength: `!:strength /N`
326    Divide(i32),
327    /// Set strength to an absolute value: `!:strength =N` or `!:strength N`
328    Set(i32),
329}
330
331/// Magic rule representation in the AST
332#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct MagicRule {
334    /// Offset specification for where to read data
335    pub offset: OffsetSpec,
336    /// Type of data to read and interpret
337    pub typ: TypeKind,
338    /// Comparison operator to apply
339    pub op: Operator,
340    /// Expected value for comparison
341    pub value: Value,
342    /// Human-readable message for this rule
343    pub message: String,
344    /// Child rules that are evaluated if this rule matches
345    pub children: Vec<MagicRule>,
346    /// Indentation level for hierarchical rules
347    pub level: u32,
348    /// Optional strength modifier from `!:strength` directive
349    pub strength_modifier: Option<StrengthModifier>,
350}
351
352// TODO: Add validation methods for MagicRule:
353// - validate() method to check rule consistency
354// - Ensure message is not empty and contains valid characters
355// - Validate that value type matches the TypeKind
356// - Check that child rule levels are properly nested
357// - Validate offset specifications are reasonable
358// - Add bounds checking for level depth to prevent stack overflow
359
360#[cfg(test)]
361mod tests {
362    use super::*;
363
364    #[test]
365    fn test_offset_spec_absolute() {
366        let offset = OffsetSpec::Absolute(42);
367        assert_eq!(offset, OffsetSpec::Absolute(42));
368
369        // Test negative offset
370        let negative = OffsetSpec::Absolute(-10);
371        assert_eq!(negative, OffsetSpec::Absolute(-10));
372    }
373
374    #[test]
375    fn test_offset_spec_indirect() {
376        let indirect = OffsetSpec::Indirect {
377            base_offset: 0x20,
378            pointer_type: TypeKind::Long {
379                endian: Endianness::Little,
380                signed: false,
381            },
382            adjustment: 4,
383            endian: Endianness::Little,
384        };
385
386        match indirect {
387            OffsetSpec::Indirect {
388                base_offset,
389                adjustment,
390                ..
391            } => {
392                assert_eq!(base_offset, 0x20);
393                assert_eq!(adjustment, 4);
394            }
395            _ => panic!("Expected Indirect variant"),
396        }
397    }
398
399    #[test]
400    fn test_offset_spec_relative() {
401        let relative = OffsetSpec::Relative(8);
402        assert_eq!(relative, OffsetSpec::Relative(8));
403
404        // Test negative relative offset
405        let negative_relative = OffsetSpec::Relative(-4);
406        assert_eq!(negative_relative, OffsetSpec::Relative(-4));
407    }
408
409    #[test]
410    fn test_offset_spec_from_end() {
411        let from_end = OffsetSpec::FromEnd(-16);
412        assert_eq!(from_end, OffsetSpec::FromEnd(-16));
413
414        // Test positive from_end (though unusual)
415        let positive_from_end = OffsetSpec::FromEnd(8);
416        assert_eq!(positive_from_end, OffsetSpec::FromEnd(8));
417    }
418
419    #[test]
420    fn test_offset_spec_debug() {
421        let offset = OffsetSpec::Absolute(100);
422        let debug_str = format!("{offset:?}");
423        assert!(debug_str.contains("Absolute"));
424        assert!(debug_str.contains("100"));
425    }
426
427    #[test]
428    fn test_offset_spec_clone() {
429        let original = OffsetSpec::Indirect {
430            base_offset: 0x10,
431            pointer_type: TypeKind::Short {
432                endian: Endianness::Big,
433                signed: true,
434            },
435            adjustment: -2,
436            endian: Endianness::Big,
437        };
438
439        let cloned = original.clone();
440        assert_eq!(original, cloned);
441    }
442
443    #[test]
444    fn test_offset_spec_serialization() {
445        let offset = OffsetSpec::Absolute(42);
446
447        // Test JSON serialization
448        let json = serde_json::to_string(&offset).expect("Failed to serialize");
449        let deserialized: OffsetSpec = serde_json::from_str(&json).expect("Failed to deserialize");
450
451        assert_eq!(offset, deserialized);
452    }
453
454    #[test]
455    fn test_offset_spec_indirect_serialization() {
456        let indirect = OffsetSpec::Indirect {
457            base_offset: 0x100,
458            pointer_type: TypeKind::Long {
459                endian: Endianness::Native,
460                signed: false,
461            },
462            adjustment: 12,
463            endian: Endianness::Native,
464        };
465
466        // Test JSON serialization for complex variant
467        let json = serde_json::to_string(&indirect).expect("Failed to serialize");
468        let deserialized: OffsetSpec = serde_json::from_str(&json).expect("Failed to deserialize");
469
470        assert_eq!(indirect, deserialized);
471    }
472
473    #[test]
474    fn test_all_offset_spec_variants() {
475        let variants = [
476            OffsetSpec::Absolute(0),
477            OffsetSpec::Absolute(-100),
478            OffsetSpec::Indirect {
479                base_offset: 0x20,
480                pointer_type: TypeKind::Byte { signed: true },
481                adjustment: 0,
482                endian: Endianness::Little,
483            },
484            OffsetSpec::Relative(50),
485            OffsetSpec::Relative(-25),
486            OffsetSpec::FromEnd(-8),
487            OffsetSpec::FromEnd(4),
488        ];
489
490        // Test that all variants can be created and are distinct
491        for (i, variant) in variants.iter().enumerate() {
492            for (j, other) in variants.iter().enumerate() {
493                if i != j {
494                    assert_ne!(
495                        variant, other,
496                        "Variants at indices {i} and {j} should be different"
497                    );
498                }
499            }
500        }
501    }
502
503    #[test]
504    fn test_endianness_variants() {
505        let endianness_values = vec![Endianness::Little, Endianness::Big, Endianness::Native];
506
507        for endian in endianness_values {
508            let indirect = OffsetSpec::Indirect {
509                base_offset: 0,
510                pointer_type: TypeKind::Long {
511                    endian,
512                    signed: false,
513                },
514                adjustment: 0,
515                endian,
516            };
517
518            // Verify the endianness is preserved
519            match indirect {
520                OffsetSpec::Indirect {
521                    endian: actual_endian,
522                    ..
523                } => {
524                    assert_eq!(endian, actual_endian);
525                }
526                _ => panic!("Expected Indirect variant"),
527            }
528        }
529    }
530
531    // Value enum tests
532    #[test]
533    fn test_value_uint() {
534        let value = Value::Uint(42);
535        assert_eq!(value, Value::Uint(42));
536
537        // Test large values
538        let large_value = Value::Uint(u64::MAX);
539        assert_eq!(large_value, Value::Uint(u64::MAX));
540    }
541
542    #[test]
543    fn test_value_int() {
544        let positive = Value::Int(100);
545        assert_eq!(positive, Value::Int(100));
546
547        let negative = Value::Int(-50);
548        assert_eq!(negative, Value::Int(-50));
549
550        // Test extreme values
551        let max_int = Value::Int(i64::MAX);
552        let min_int = Value::Int(i64::MIN);
553        assert_eq!(max_int, Value::Int(i64::MAX));
554        assert_eq!(min_int, Value::Int(i64::MIN));
555    }
556
557    #[test]
558    fn test_value_bytes() {
559        let empty_bytes = Value::Bytes(vec![]);
560        assert_eq!(empty_bytes, Value::Bytes(vec![]));
561
562        let some_bytes = Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]);
563        assert_eq!(some_bytes, Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]));
564
565        // Test that different byte sequences are not equal
566        let other_bytes = Value::Bytes(vec![0x50, 0x4b, 0x03, 0x04]);
567        assert_ne!(some_bytes, other_bytes);
568    }
569
570    #[test]
571    fn test_value_string() {
572        let empty_string = Value::String(String::new());
573        assert_eq!(empty_string, Value::String(String::new()));
574
575        let hello = Value::String("Hello, World!".to_string());
576        assert_eq!(hello, Value::String("Hello, World!".to_string()));
577
578        // Test Unicode strings
579        let unicode = Value::String("🦀 Rust".to_string());
580        assert_eq!(unicode, Value::String("🦀 Rust".to_string()));
581    }
582
583    #[test]
584    fn test_value_comparison() {
585        // Test that different value types are not equal
586        let uint_val = Value::Uint(42);
587        let int_val = Value::Int(42);
588        let bytes_val = Value::Bytes(vec![42]);
589        let string_val = Value::String("42".to_string());
590
591        assert_ne!(uint_val, int_val);
592        assert_ne!(uint_val, bytes_val);
593        assert_ne!(uint_val, string_val);
594        assert_ne!(int_val, bytes_val);
595        assert_ne!(int_val, string_val);
596        assert_ne!(bytes_val, string_val);
597    }
598
599    #[test]
600    fn test_value_debug() {
601        let uint_val = Value::Uint(123);
602        let debug_str = format!("{uint_val:?}");
603        assert!(debug_str.contains("Uint"));
604        assert!(debug_str.contains("123"));
605
606        let string_val = Value::String("test".to_string());
607        let debug_str = format!("{string_val:?}");
608        assert!(debug_str.contains("String"));
609        assert!(debug_str.contains("test"));
610    }
611
612    #[test]
613    fn test_value_clone() {
614        let original = Value::Bytes(vec![1, 2, 3, 4]);
615        let cloned = original.clone();
616        assert_eq!(original, cloned);
617
618        // Verify they are independent copies
619        match (original, cloned) {
620            (Value::Bytes(orig_bytes), Value::Bytes(cloned_bytes)) => {
621                assert_eq!(orig_bytes, cloned_bytes);
622                // They should have the same content but be different Vec instances
623            }
624            _ => panic!("Expected Bytes variants"),
625        }
626    }
627
628    #[test]
629    fn test_value_serialization() {
630        let values = vec![
631            Value::Uint(42),
632            Value::Int(-100),
633            Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
634            Value::String("ELF executable".to_string()),
635        ];
636
637        for value in values {
638            // Test JSON serialization
639            let json = serde_json::to_string(&value).expect("Failed to serialize Value");
640            let deserialized: Value =
641                serde_json::from_str(&json).expect("Failed to deserialize Value");
642            assert_eq!(value, deserialized);
643        }
644    }
645
646    #[test]
647    fn test_value_serialization_edge_cases() {
648        // Test empty collections
649        let empty_bytes = Value::Bytes(vec![]);
650        let json = serde_json::to_string(&empty_bytes).expect("Failed to serialize empty bytes");
651        let deserialized: Value =
652            serde_json::from_str(&json).expect("Failed to deserialize empty bytes");
653        assert_eq!(empty_bytes, deserialized);
654
655        let empty_string = Value::String(String::new());
656        let json = serde_json::to_string(&empty_string).expect("Failed to serialize empty string");
657        let deserialized: Value =
658            serde_json::from_str(&json).expect("Failed to deserialize empty string");
659        assert_eq!(empty_string, deserialized);
660
661        // Test extreme values
662        let max_uint = Value::Uint(u64::MAX);
663        let json = serde_json::to_string(&max_uint).expect("Failed to serialize max uint");
664        let deserialized: Value =
665            serde_json::from_str(&json).expect("Failed to deserialize max uint");
666        assert_eq!(max_uint, deserialized);
667
668        let min_int = Value::Int(i64::MIN);
669        let json = serde_json::to_string(&min_int).expect("Failed to serialize min int");
670        let deserialized: Value =
671            serde_json::from_str(&json).expect("Failed to deserialize min int");
672        assert_eq!(min_int, deserialized);
673    }
674
675    // TypeKind tests
676    #[test]
677    fn test_type_kind_byte() {
678        let byte_type = TypeKind::Byte { signed: true };
679        assert_eq!(byte_type, TypeKind::Byte { signed: true });
680    }
681
682    #[test]
683    fn test_type_kind_short() {
684        let short_little_endian = TypeKind::Short {
685            endian: Endianness::Little,
686            signed: false,
687        };
688        let short_big_endian = TypeKind::Short {
689            endian: Endianness::Big,
690            signed: true,
691        };
692
693        assert_ne!(short_little_endian, short_big_endian);
694        assert_eq!(short_little_endian, short_little_endian.clone());
695    }
696
697    #[test]
698    fn test_type_kind_long() {
699        let long_native = TypeKind::Long {
700            endian: Endianness::Native,
701            signed: true,
702        };
703
704        match long_native {
705            TypeKind::Long { endian, signed } => {
706                assert_eq!(endian, Endianness::Native);
707                assert!(signed);
708            }
709            _ => panic!("Expected Long variant"),
710        }
711    }
712
713    #[test]
714    fn test_type_kind_string() {
715        let unlimited_string = TypeKind::String { max_length: None };
716        let limited_string = TypeKind::String {
717            max_length: Some(256),
718        };
719
720        assert_ne!(unlimited_string, limited_string);
721        assert_eq!(unlimited_string, unlimited_string.clone());
722    }
723
724    #[test]
725    fn test_type_kind_serialization() {
726        let types = vec![
727            TypeKind::Byte { signed: true },
728            TypeKind::Short {
729                endian: Endianness::Little,
730                signed: false,
731            },
732            TypeKind::Long {
733                endian: Endianness::Big,
734                signed: true,
735            },
736            TypeKind::Quad {
737                endian: Endianness::Little,
738                signed: false,
739            },
740            TypeKind::Quad {
741                endian: Endianness::Big,
742                signed: true,
743            },
744            TypeKind::String { max_length: None },
745            TypeKind::String {
746                max_length: Some(128),
747            },
748        ];
749
750        for typ in types {
751            let json = serde_json::to_string(&typ).expect("Failed to serialize TypeKind");
752            let deserialized: TypeKind =
753                serde_json::from_str(&json).expect("Failed to deserialize TypeKind");
754            assert_eq!(typ, deserialized);
755        }
756    }
757
758    // Operator tests
759    #[test]
760    fn test_operator_variants() {
761        let operators = [
762            Operator::Equal,
763            Operator::NotEqual,
764            Operator::BitwiseAnd,
765            Operator::BitwiseXor,
766            Operator::BitwiseNot,
767            Operator::AnyValue,
768        ];
769
770        for (i, op) in operators.iter().enumerate() {
771            for (j, other) in operators.iter().enumerate() {
772                if i == j {
773                    assert_eq!(op, other);
774                } else {
775                    assert_ne!(op, other);
776                }
777            }
778        }
779    }
780
781    #[test]
782    fn test_operator_serialization() {
783        let operators = vec![
784            Operator::Equal,
785            Operator::NotEqual,
786            Operator::BitwiseAnd,
787            Operator::BitwiseXor,
788            Operator::BitwiseNot,
789            Operator::AnyValue,
790        ];
791
792        for op in operators {
793            let json = serde_json::to_string(&op).expect("Failed to serialize Operator");
794            let deserialized: Operator =
795                serde_json::from_str(&json).expect("Failed to deserialize Operator");
796            assert_eq!(op, deserialized);
797        }
798    }
799
800    // MagicRule tests
801    #[test]
802    fn test_magic_rule_creation() {
803        let rule = MagicRule {
804            offset: OffsetSpec::Absolute(0),
805            typ: TypeKind::Byte { signed: true },
806            op: Operator::Equal,
807            value: Value::Uint(0x7f),
808            message: "ELF magic".to_string(),
809            children: vec![],
810            level: 0,
811            strength_modifier: None,
812        };
813
814        assert_eq!(rule.message, "ELF magic");
815        assert_eq!(rule.level, 0);
816        assert!(rule.children.is_empty());
817    }
818
819    #[test]
820    fn test_magic_rule_with_children() {
821        let child_rule = MagicRule {
822            offset: OffsetSpec::Absolute(4),
823            typ: TypeKind::Byte { signed: true },
824            op: Operator::Equal,
825            value: Value::Uint(1),
826            message: "32-bit".to_string(),
827            children: vec![],
828            level: 1,
829            strength_modifier: None,
830        };
831
832        let parent_rule = MagicRule {
833            offset: OffsetSpec::Absolute(0),
834            typ: TypeKind::Long {
835                endian: Endianness::Little,
836                signed: false,
837            },
838            op: Operator::Equal,
839            value: Value::Bytes(vec![0x7f, 0x45, 0x4c, 0x46]),
840            message: "ELF executable".to_string(),
841            children: vec![child_rule],
842            level: 0,
843            strength_modifier: None,
844        };
845
846        assert_eq!(parent_rule.children.len(), 1);
847        assert_eq!(parent_rule.children[0].level, 1);
848        assert_eq!(parent_rule.children[0].message, "32-bit");
849    }
850
851    #[test]
852    fn test_magic_rule_serialization() {
853        let rule = MagicRule {
854            offset: OffsetSpec::Absolute(16),
855            typ: TypeKind::Short {
856                endian: Endianness::Little,
857                signed: false,
858            },
859            op: Operator::NotEqual,
860            value: Value::Uint(0),
861            message: "Non-zero short value".to_string(),
862            children: vec![],
863            level: 2,
864            strength_modifier: None,
865        };
866
867        let json = serde_json::to_string(&rule).expect("Failed to serialize MagicRule");
868        let deserialized: MagicRule =
869            serde_json::from_str(&json).expect("Failed to deserialize MagicRule");
870
871        assert_eq!(rule.message, deserialized.message);
872        assert_eq!(rule.level, deserialized.level);
873        assert_eq!(rule.children.len(), deserialized.children.len());
874    }
875
876    // StrengthModifier tests
877    #[test]
878    fn test_strength_modifier_variants() {
879        let add = StrengthModifier::Add(10);
880        let sub = StrengthModifier::Subtract(5);
881        let mul = StrengthModifier::Multiply(2);
882        let div = StrengthModifier::Divide(2);
883        let set = StrengthModifier::Set(50);
884
885        // Test that each variant has the correct inner value
886        assert_eq!(add, StrengthModifier::Add(10));
887        assert_eq!(sub, StrengthModifier::Subtract(5));
888        assert_eq!(mul, StrengthModifier::Multiply(2));
889        assert_eq!(div, StrengthModifier::Divide(2));
890        assert_eq!(set, StrengthModifier::Set(50));
891
892        // Test that different variants are not equal
893        assert_ne!(add, sub);
894        assert_ne!(mul, div);
895        assert_ne!(set, add);
896    }
897
898    #[test]
899    fn test_strength_modifier_negative_values() {
900        let add_negative = StrengthModifier::Add(-10);
901        let sub_negative = StrengthModifier::Subtract(-5);
902        let set_negative = StrengthModifier::Set(-50);
903
904        assert_eq!(add_negative, StrengthModifier::Add(-10));
905        assert_eq!(sub_negative, StrengthModifier::Subtract(-5));
906        assert_eq!(set_negative, StrengthModifier::Set(-50));
907    }
908
909    #[test]
910    fn test_strength_modifier_serialization() {
911        let modifiers = vec![
912            StrengthModifier::Add(10),
913            StrengthModifier::Subtract(5),
914            StrengthModifier::Multiply(2),
915            StrengthModifier::Divide(3),
916            StrengthModifier::Set(100),
917        ];
918
919        for modifier in modifiers {
920            let json =
921                serde_json::to_string(&modifier).expect("Failed to serialize StrengthModifier");
922            let deserialized: StrengthModifier =
923                serde_json::from_str(&json).expect("Failed to deserialize StrengthModifier");
924            assert_eq!(modifier, deserialized);
925        }
926    }
927
928    #[test]
929    fn test_strength_modifier_debug() {
930        let modifier = StrengthModifier::Add(25);
931        let debug_str = format!("{modifier:?}");
932        assert!(debug_str.contains("Add"));
933        assert!(debug_str.contains("25"));
934    }
935
936    #[test]
937    fn test_strength_modifier_clone() {
938        let original = StrengthModifier::Multiply(4);
939        let cloned = original;
940        assert_eq!(original, cloned);
941    }
942
943    #[test]
944    fn test_magic_rule_with_strength_modifier() {
945        let rule = MagicRule {
946            offset: OffsetSpec::Absolute(0),
947            typ: TypeKind::Byte { signed: true },
948            op: Operator::Equal,
949            value: Value::Uint(0x7f),
950            message: "ELF magic".to_string(),
951            children: vec![],
952            level: 0,
953            strength_modifier: Some(StrengthModifier::Add(20)),
954        };
955
956        assert_eq!(rule.strength_modifier, Some(StrengthModifier::Add(20)));
957
958        // Test serialization with strength_modifier
959        let json = serde_json::to_string(&rule).expect("Failed to serialize MagicRule");
960        let deserialized: MagicRule =
961            serde_json::from_str(&json).expect("Failed to deserialize MagicRule");
962        assert_eq!(rule.strength_modifier, deserialized.strength_modifier);
963    }
964
965    #[test]
966    fn test_magic_rule_without_strength_modifier() {
967        let rule = MagicRule {
968            offset: OffsetSpec::Absolute(0),
969            typ: TypeKind::Byte { signed: true },
970            op: Operator::Equal,
971            value: Value::Uint(0x7f),
972            message: "ELF magic".to_string(),
973            children: vec![],
974            level: 0,
975            strength_modifier: None,
976        };
977
978        assert_eq!(rule.strength_modifier, None);
979    }
980}