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