Skip to main content

riglr_events_core/
parser.rs

1//! Event parsing utilities and base implementations.
2
3use crate::error::{EventError, EventResult};
4use crate::traits::{Event, EventParser, ParserInfo};
5use crate::types::{EventKind, EventMetadata, GenericEvent};
6use async_trait::async_trait;
7use regex::Regex;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::Arc;
11
12/// Configuration for parsing events from different data sources.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ParsingConfig {
15    /// Parser name
16    pub name: String,
17    /// Parser version
18    pub version: String,
19    /// Data format (e.g., "json", "binary", "xml")
20    pub format: String,
21    /// Field mappings for extracting event data
22    pub field_mappings: HashMap<String, String>,
23    /// Default values for missing fields
24    pub defaults: HashMap<String, serde_json::Value>,
25    /// Validation rules
26    pub validation: ValidationConfig,
27}
28
29impl ParsingConfig {
30    /// Create a new parsing configuration
31    pub fn new(name: String, version: String, format: String) -> Self {
32        Self {
33            name,
34            version,
35            format,
36            field_mappings: HashMap::new(),
37            defaults: HashMap::new(),
38            validation: ValidationConfig::default(),
39        }
40    }
41
42    /// Add a field mapping
43    pub fn with_mapping(mut self, field: String, source_path: String) -> Self {
44        self.field_mappings.insert(field, source_path);
45        self
46    }
47
48    /// Add a default value
49    pub fn with_default<T: Serialize>(mut self, field: String, value: T) -> Self {
50        if let Ok(json_value) = serde_json::to_value(value) {
51            self.defaults.insert(field, json_value);
52        }
53        self
54    }
55
56    /// Set validation configuration
57    pub fn with_validation(mut self, validation: ValidationConfig) -> Self {
58        self.validation = validation;
59        self
60    }
61}
62
63/// Validation configuration for parsed events.
64#[derive(Debug, Clone, Serialize, Deserialize, Default)]
65pub struct ValidationConfig {
66    /// Required fields that must be present
67    pub required_fields: Vec<String>,
68    /// Field type constraints
69    pub field_types: HashMap<String, String>,
70    /// Minimum values for numeric fields
71    pub min_values: HashMap<String, f64>,
72    /// Maximum values for numeric fields
73    pub max_values: HashMap<String, f64>,
74    /// Regex patterns for string fields
75    pub patterns: HashMap<String, String>,
76}
77
78impl ValidationConfig {
79    /// Add a required field
80    pub fn with_required(mut self, field: String) -> Self {
81        self.required_fields.push(field);
82        self
83    }
84
85    /// Add a field type constraint
86    pub fn with_type(mut self, field: String, type_name: String) -> Self {
87        self.field_types.insert(field, type_name);
88        self
89    }
90
91    /// Add a numeric range constraint
92    pub fn with_range(mut self, field: String, min: f64, max: f64) -> Self {
93        self.min_values.insert(field.clone(), min);
94        self.max_values.insert(field, max);
95        self
96    }
97
98    /// Add a regex pattern constraint
99    pub fn with_pattern(mut self, field: String, pattern: String) -> Self {
100        self.patterns.insert(field, pattern);
101        self
102    }
103}
104
105/// JSON-based event parser implementation.
106pub struct JsonEventParser {
107    config: ParsingConfig,
108    event_kind: EventKind,
109    source_name: String,
110}
111
112impl JsonEventParser {
113    /// Create a new JSON event parser
114    pub fn new(config: ParsingConfig, event_kind: EventKind, source_name: String) -> Self {
115        Self {
116            config,
117            event_kind,
118            source_name,
119        }
120    }
121
122    /// Extract a field from JSON using JSONPath-like syntax
123    fn extract_field(&self, data: &serde_json::Value, path: &str) -> Option<serde_json::Value> {
124        let parts: Vec<&str> = path.split('.').collect();
125        let mut current = data;
126
127        for part in parts {
128            match current {
129                serde_json::Value::Object(obj) => {
130                    current = obj.get(part)?;
131                }
132                serde_json::Value::Array(arr) => {
133                    if let Ok(index) = part.parse::<usize>() {
134                        current = arr.get(index)?;
135                    } else {
136                        return None;
137                    }
138                }
139                _ => return None,
140            }
141        }
142
143        Some(current.clone())
144    }
145
146    /// Apply field mappings to raw data
147    fn apply_mappings(&self, data: &serde_json::Value) -> EventResult<serde_json::Value> {
148        let mut result = serde_json::Map::new();
149
150        // Apply field mappings
151        for (field, source_path) in &self.config.field_mappings {
152            if let Some(value) = self.extract_field(data, source_path) {
153                result.insert(field.clone(), value);
154            }
155        }
156
157        // Apply defaults for missing fields
158        for (field, default_value) in &self.config.defaults {
159            if !result.contains_key(field) {
160                result.insert(field.clone(), default_value.clone());
161            }
162        }
163
164        Ok(serde_json::Value::Object(result))
165    }
166
167    /// Validate extracted data against configuration rules
168    fn validate(&self, data: &serde_json::Value) -> EventResult<()> {
169        let obj = data.as_object().ok_or_else(|| {
170            EventError::parse_error(
171                std::io::Error::new(std::io::ErrorKind::InvalidData, "Expected object"),
172                "Data is not a JSON object",
173            )
174        })?;
175
176        self.validate_required_fields(obj)?;
177        self.validate_field_types(obj)?;
178        self.validate_numeric_ranges(obj)?;
179        self.validate_string_patterns(obj)?;
180
181        Ok(())
182    }
183
184    /// Validate that all required fields are present
185    fn validate_required_fields(
186        &self,
187        obj: &serde_json::Map<String, serde_json::Value>,
188    ) -> EventResult<()> {
189        for required_field in &self.config.validation.required_fields {
190            if !obj.contains_key(required_field) {
191                return Err(EventError::parse_error(
192                    std::io::Error::new(
193                        std::io::ErrorKind::InvalidData,
194                        format!("Missing required field: {}", required_field),
195                    ),
196                    format!("Required field '{}' is missing", required_field),
197                ));
198            }
199        }
200        Ok(())
201    }
202
203    /// Validate field types match expected types
204    fn validate_field_types(
205        &self,
206        obj: &serde_json::Map<String, serde_json::Value>,
207    ) -> EventResult<()> {
208        for (field, expected_type) in &self.config.validation.field_types {
209            if let Some(value) = obj.get(field) {
210                let actual_type = self.get_json_type(value);
211                if actual_type != expected_type {
212                    return Err(EventError::parse_error(
213                        std::io::Error::new(
214                            std::io::ErrorKind::InvalidData,
215                            format!(
216                                "Type mismatch for field '{}': expected {}, got {}",
217                                field, expected_type, actual_type
218                            ),
219                        ),
220                        format!("Field '{}' has wrong type", field),
221                    ));
222                }
223            }
224        }
225        Ok(())
226    }
227
228    /// Get the string representation of a JSON value's type
229    fn get_json_type(&self, value: &serde_json::Value) -> &'static str {
230        match value {
231            serde_json::Value::String(_) => "string",
232            serde_json::Value::Number(_) => "number",
233            serde_json::Value::Bool(_) => "boolean",
234            serde_json::Value::Array(_) => "array",
235            serde_json::Value::Object(_) => "object",
236            serde_json::Value::Null => "null",
237        }
238    }
239
240    /// Validate numeric fields are within specified ranges
241    fn validate_numeric_ranges(
242        &self,
243        obj: &serde_json::Map<String, serde_json::Value>,
244    ) -> EventResult<()> {
245        self.validate_minimum_values(obj)?;
246        self.validate_maximum_values(obj)?;
247        Ok(())
248    }
249
250    /// Validate minimum values for numeric fields
251    fn validate_minimum_values(
252        &self,
253        obj: &serde_json::Map<String, serde_json::Value>,
254    ) -> EventResult<()> {
255        for (field, min_value) in &self.config.validation.min_values {
256            if let Some(value) = obj.get(field) {
257                if let Some(num) = value.as_f64() {
258                    if num < *min_value {
259                        return Err(EventError::parse_error(
260                            std::io::Error::new(
261                                std::io::ErrorKind::InvalidData,
262                                format!(
263                                    "Value {} for field '{}' is below minimum {}",
264                                    num, field, min_value
265                                ),
266                            ),
267                            format!("Field '{}' value too small", field),
268                        ));
269                    }
270                }
271            }
272        }
273        Ok(())
274    }
275
276    /// Validate maximum values for numeric fields
277    fn validate_maximum_values(
278        &self,
279        obj: &serde_json::Map<String, serde_json::Value>,
280    ) -> EventResult<()> {
281        for (field, max_value) in &self.config.validation.max_values {
282            if let Some(value) = obj.get(field) {
283                if let Some(num) = value.as_f64() {
284                    if num > *max_value {
285                        return Err(EventError::parse_error(
286                            std::io::Error::new(
287                                std::io::ErrorKind::InvalidData,
288                                format!(
289                                    "Value {} for field '{}' is above maximum {}",
290                                    num, field, max_value
291                                ),
292                            ),
293                            format!("Field '{}' value too large", field),
294                        ));
295                    }
296                }
297            }
298        }
299        Ok(())
300    }
301
302    /// Validate string fields match specified regex patterns
303    fn validate_string_patterns(
304        &self,
305        obj: &serde_json::Map<String, serde_json::Value>,
306    ) -> EventResult<()> {
307        for (field, pattern) in &self.config.validation.patterns {
308            if let Some(value) = obj.get(field) {
309                if let Some(string_value) = value.as_str() {
310                    self.validate_regex_pattern(field, string_value, pattern)?;
311                }
312            }
313        }
314        Ok(())
315    }
316
317    /// Validate a single string against a regex pattern
318    fn validate_regex_pattern(
319        &self,
320        field: &str,
321        string_value: &str,
322        pattern: &str,
323    ) -> EventResult<()> {
324        match Regex::new(pattern) {
325            Ok(regex) => {
326                if !regex.is_match(string_value) {
327                    return Err(EventError::parse_error(
328                        std::io::Error::new(
329                            std::io::ErrorKind::InvalidData,
330                            format!(
331                                "String '{}' for field '{}' doesn't match pattern '{}'",
332                                string_value, field, pattern
333                            ),
334                        ),
335                        format!("Field '{}' doesn't match pattern", field),
336                    ));
337                }
338            }
339            Err(regex_error) => {
340                return Err(EventError::parse_error(
341                    std::io::Error::new(
342                        std::io::ErrorKind::InvalidData,
343                        format!(
344                            "Invalid regex pattern '{}' for field '{}': {}",
345                            pattern, field, regex_error
346                        ),
347                    ),
348                    format!("Invalid regex pattern for field '{}'", field),
349                ));
350            }
351        }
352        Ok(())
353    }
354}
355
356#[async_trait]
357impl EventParser for JsonEventParser {
358    type Input = serde_json::Value;
359
360    async fn parse(&self, input: Self::Input) -> EventResult<Vec<Box<dyn Event>>> {
361        // Apply field mappings and defaults
362        let mapped_data = self.apply_mappings(&input)?;
363
364        // Validate the mapped data
365        self.validate(&mapped_data)?;
366
367        // Create event metadata
368        let event_id = mapped_data
369            .get("id")
370            .and_then(|v| v.as_str())
371            .map(|s| s.to_string())
372            .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
373
374        let metadata =
375            EventMetadata::new(event_id, self.event_kind.clone(), self.source_name.clone());
376
377        // Create the event
378        let event = GenericEvent::with_metadata(metadata, mapped_data);
379
380        Ok(vec![Box::new(event)])
381    }
382
383    fn can_parse(&self, input: &Self::Input) -> bool {
384        // Check if input has expected structure based on field mappings
385        for source_path in self.config.field_mappings.values() {
386            if self.extract_field(input, source_path).is_none() {
387                return false;
388            }
389        }
390        true
391    }
392
393    fn info(&self) -> ParserInfo {
394        ParserInfo::new(self.config.name.clone(), self.config.version.clone())
395            .with_kind(self.event_kind.clone())
396            .with_format(self.config.format.clone())
397    }
398}
399
400/// Multi-format parser that can handle different data formats.
401pub struct MultiFormatParser {
402    parsers: HashMap<String, Arc<dyn EventParser<Input = Vec<u8>> + Send + Sync>>,
403    default_format: String,
404}
405
406impl MultiFormatParser {
407    /// Create a new multi-format parser
408    pub fn new(default_format: String) -> Self {
409        Self {
410            parsers: HashMap::new(),
411            default_format,
412        }
413    }
414
415    /// Add a parser for a specific format
416    pub fn with_parser<P>(mut self, format: String, parser: P) -> Self
417    where
418        P: EventParser<Input = Vec<u8>> + Send + Sync + 'static,
419    {
420        self.parsers.insert(format, Arc::new(parser));
421        self
422    }
423
424    /// Detect format from data content
425    fn detect_format(&self, data: &[u8]) -> String {
426        // Simple format detection - can be made more sophisticated
427        if data.starts_with(b"{") || data.starts_with(b"[") {
428            "json".to_string()
429        } else if data.starts_with(b"<") {
430            "xml".to_string()
431        } else {
432            self.default_format.clone()
433        }
434    }
435}
436
437#[async_trait]
438impl EventParser for MultiFormatParser {
439    type Input = Vec<u8>;
440
441    async fn parse(&self, input: Self::Input) -> EventResult<Vec<Box<dyn Event>>> {
442        let format = self.detect_format(&input);
443
444        if let Some(parser) = self.parsers.get(&format) {
445            parser.parse(input).await
446        } else {
447            Err(EventError::parse_error(
448                std::io::Error::new(std::io::ErrorKind::NotFound, "Parser not found"),
449                format!("No parser available for format: {}", format),
450            ))
451        }
452    }
453
454    fn can_parse(&self, input: &Self::Input) -> bool {
455        let format = self.detect_format(input);
456        self.parsers
457            .get(&format)
458            .is_some_and(|p| p.can_parse(input))
459    }
460
461    fn info(&self) -> ParserInfo {
462        ParserInfo::new("multi-format".to_string(), "1.0.0".to_string())
463            .with_format("json".to_string())
464            .with_format("xml".to_string())
465            .with_format("binary".to_string())
466    }
467}
468
469/// Binary data parser for handling raw bytes.
470pub struct BinaryEventParser {
471    name: String,
472    version: String,
473    event_kind: EventKind,
474    source_name: String,
475}
476
477impl BinaryEventParser {
478    /// Create a new binary event parser
479    pub fn new(name: String, version: String, event_kind: EventKind, source_name: String) -> Self {
480        Self {
481            name,
482            version,
483            event_kind,
484            source_name,
485        }
486    }
487}
488
489#[async_trait]
490impl EventParser for BinaryEventParser {
491    type Input = Vec<u8>;
492
493    async fn parse(&self, input: Self::Input) -> EventResult<Vec<Box<dyn Event>>> {
494        // Create metadata for binary data
495        let event_id = format!("binary_{}", uuid::Uuid::new_v4());
496        let metadata =
497            EventMetadata::new(event_id, self.event_kind.clone(), self.source_name.clone());
498
499        // Convert binary data to hex representation for storage
500        let hex_data = hex::encode(&input);
501        let data = serde_json::json!({
502            "format": "binary",
503            "hex": hex_data,
504            "length": input.len()
505        });
506
507        let event = GenericEvent::with_metadata(metadata, data);
508        Ok(vec![Box::new(event)])
509    }
510
511    fn can_parse(&self, _input: &Self::Input) -> bool {
512        true // Can always parse binary data
513    }
514
515    fn info(&self) -> ParserInfo {
516        ParserInfo::new(self.name.clone(), self.version.clone())
517            .with_kind(self.event_kind.clone())
518            .with_format("binary".to_string())
519    }
520}
521
522#[cfg(test)]
523mod tests {
524    use super::*;
525    use crate::types::EventKind;
526    use serde_json::json;
527
528    #[tokio::test]
529    async fn test_json_parser_basic() {
530        let config = ParsingConfig::new(
531            "test-parser".to_string(),
532            "1.0.0".to_string(),
533            "json".to_string(),
534        )
535        .with_mapping("amount".to_string(), "transaction.amount".to_string())
536        .with_mapping("token".to_string(), "transaction.token".to_string())
537        .with_default("fee".to_string(), 0.01);
538
539        let parser =
540            JsonEventParser::new(config, EventKind::Transaction, "test-source".to_string());
541
542        let input = json!({
543            "transaction": {
544                "amount": 100,
545                "token": "USDC"
546            }
547        });
548
549        let events = parser.parse(input).await.unwrap();
550        assert_eq!(events.len(), 1);
551
552        let event = &events[0];
553        assert_eq!(event.kind(), &EventKind::Transaction);
554        assert_eq!(event.source(), "test-source");
555    }
556
557    #[tokio::test]
558    async fn test_json_parser_validation() {
559        let config = ParsingConfig::new(
560            "test-parser".to_string(),
561            "1.0.0".to_string(),
562            "json".to_string(),
563        )
564        .with_mapping("amount".to_string(), "amount".to_string())
565        .with_validation(
566            ValidationConfig::default()
567                .with_required("amount".to_string())
568                .with_range("amount".to_string(), 0.0, 1000.0),
569        );
570
571        let parser =
572            JsonEventParser::new(config, EventKind::Transaction, "test-source".to_string());
573
574        // Test missing required field
575        let input = json!({"other": "value"});
576        let result = parser.parse(input).await;
577        assert!(result.is_err());
578
579        // Test valid input
580        let input = json!({"amount": 100});
581        let result = parser.parse(input).await;
582        assert!(result.is_ok());
583
584        // Test out of range value
585        let input = json!({"amount": 2000});
586        let result = parser.parse(input).await;
587        assert!(result.is_err());
588    }
589
590    #[tokio::test]
591    async fn test_binary_parser() {
592        let parser = BinaryEventParser::new(
593            "binary-parser".to_string(),
594            "1.0.0".to_string(),
595            EventKind::Contract,
596            "binary-source".to_string(),
597        );
598
599        let input = vec![0x01, 0x02, 0x03, 0x04];
600        let events = parser.parse(input.clone()).await.unwrap();
601
602        assert_eq!(events.len(), 1);
603        let event = &events[0];
604        assert_eq!(event.kind(), &EventKind::Contract);
605        assert_eq!(event.source(), "binary-source");
606    }
607
608    #[test]
609    fn test_parsing_config_builder() {
610        let config =
611            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
612                .with_mapping("field1".to_string(), "source.field1".to_string())
613                .with_default("field2".to_string(), "default_value")
614                .with_validation(
615                    ValidationConfig::default()
616                        .with_required("field1".to_string())
617                        .with_type("field1".to_string(), "string".to_string()),
618                );
619
620        assert_eq!(config.field_mappings.len(), 1);
621        assert_eq!(config.defaults.len(), 1);
622        assert_eq!(config.validation.required_fields.len(), 1);
623        assert_eq!(config.validation.field_types.len(), 1);
624    }
625
626    #[test]
627    fn test_validation_config_builder() {
628        let validation = ValidationConfig::default()
629            .with_required("amount".to_string())
630            .with_type("amount".to_string(), "number".to_string())
631            .with_range("amount".to_string(), 0.0, 1000.0)
632            .with_pattern("token".to_string(), "^[A-Z]+$".to_string());
633
634        assert_eq!(validation.required_fields.len(), 1);
635        assert_eq!(validation.field_types.len(), 1);
636        assert_eq!(validation.min_values.len(), 1);
637        assert_eq!(validation.max_values.len(), 1);
638        assert_eq!(validation.patterns.len(), 1);
639    }
640
641    // Additional comprehensive tests for 100% coverage
642
643    #[test]
644    fn test_parsing_config_with_default_serialization_error() {
645        // Test with a value that cannot be serialized to JSON
646        let config =
647            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
648        // This should not add the default since serialization would fail for certain types
649        // but our current implementation uses serde_json::to_value which handles most types
650        let config = config.with_default("field".to_string(), "valid_string");
651        assert_eq!(config.defaults.len(), 1);
652    }
653
654    #[test]
655    fn test_json_parser_extract_field_nested_object() {
656        let config =
657            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
658        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
659
660        let data = json!({
661            "level1": {
662                "level2": {
663                    "value": "found"
664                }
665            }
666        });
667
668        let result = parser.extract_field(&data, "level1.level2.value");
669        assert_eq!(result, Some(json!("found")));
670    }
671
672    #[test]
673    fn test_json_parser_extract_field_array_access() {
674        let config =
675            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
676        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
677
678        let data = json!({
679            "items": [
680                {"name": "first"},
681                {"name": "second"}
682            ]
683        });
684
685        let result = parser.extract_field(&data, "items.0.name");
686        assert_eq!(result, Some(json!("first")));
687
688        let result = parser.extract_field(&data, "items.1.name");
689        assert_eq!(result, Some(json!("second")));
690    }
691
692    #[test]
693    fn test_json_parser_extract_field_array_invalid_index() {
694        let config =
695            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
696        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
697
698        let data = json!({
699            "items": [{"name": "first"}]
700        });
701
702        // Index out of bounds
703        let result = parser.extract_field(&data, "items.5.name");
704        assert_eq!(result, None);
705
706        // Non-numeric index on array
707        let result = parser.extract_field(&data, "items.invalid.name");
708        assert_eq!(result, None);
709    }
710
711    #[test]
712    fn test_json_parser_extract_field_invalid_path() {
713        let config =
714            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
715        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
716
717        let data = json!({
718            "value": "string"
719        });
720
721        // Trying to access property on string
722        let result = parser.extract_field(&data, "value.nonexistent");
723        assert_eq!(result, None);
724
725        // Non-existent path
726        let result = parser.extract_field(&data, "nonexistent.path");
727        assert_eq!(result, None);
728    }
729
730    #[test]
731    fn test_json_parser_extract_field_empty_path() {
732        let config =
733            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
734        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
735
736        let data = json!({"key": "value"});
737
738        // Single part path
739        let result = parser.extract_field(&data, "key");
740        assert_eq!(result, Some(json!("value")));
741    }
742
743    #[tokio::test]
744    async fn test_json_parser_validation_missing_required() {
745        let config =
746            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
747                .with_validation(
748                    ValidationConfig::default().with_required("required_field".to_string()),
749                );
750
751        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
752        let input = json!({"other_field": "value"});
753
754        let result = parser.parse(input).await;
755        assert!(result.is_err());
756
757        if let Err(EventError::ParseError { context, .. }) = result {
758            assert!(context.contains("Required field 'required_field' is missing"));
759        } else {
760            panic!("Expected ParseError");
761        }
762    }
763
764    #[tokio::test]
765    async fn test_json_parser_validation_type_mismatch() {
766        let config =
767            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
768                .with_mapping("field".to_string(), "field".to_string())
769                .with_validation(
770                    ValidationConfig::default()
771                        .with_type("field".to_string(), "string".to_string()),
772                );
773
774        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
775        let input = json!({"field": 123}); // number instead of string
776
777        let result = parser.parse(input).await;
778        assert!(result.is_err());
779
780        if let Err(EventError::ParseError { context, .. }) = result {
781            assert!(context.contains("Field 'field' has wrong type"));
782        } else {
783            panic!("Expected ParseError");
784        }
785    }
786
787    #[tokio::test]
788    async fn test_json_parser_validation_all_types() {
789        let config =
790            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
791                .with_mapping("str_field".to_string(), "str_field".to_string())
792                .with_mapping("num_field".to_string(), "num_field".to_string())
793                .with_mapping("bool_field".to_string(), "bool_field".to_string())
794                .with_mapping("arr_field".to_string(), "arr_field".to_string())
795                .with_mapping("obj_field".to_string(), "obj_field".to_string())
796                .with_mapping("null_field".to_string(), "null_field".to_string())
797                .with_validation(
798                    ValidationConfig::default()
799                        .with_type("str_field".to_string(), "string".to_string())
800                        .with_type("num_field".to_string(), "number".to_string())
801                        .with_type("bool_field".to_string(), "boolean".to_string())
802                        .with_type("arr_field".to_string(), "array".to_string())
803                        .with_type("obj_field".to_string(), "object".to_string())
804                        .with_type("null_field".to_string(), "null".to_string()),
805                );
806
807        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
808        let input = json!({
809            "str_field": "string",
810            "num_field": 123,
811            "bool_field": true,
812            "arr_field": [1, 2, 3],
813            "obj_field": {"key": "value"},
814            "null_field": null
815        });
816
817        let result = parser.parse(input).await;
818        assert!(result.is_ok());
819    }
820
821    #[tokio::test]
822    async fn test_json_parser_validation_numeric_range_below_min() {
823        let config =
824            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
825                .with_mapping("amount".to_string(), "amount".to_string())
826                .with_validation(ValidationConfig::default().with_range(
827                    "amount".to_string(),
828                    10.0,
829                    100.0,
830                ));
831
832        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
833        let input = json!({"amount": 5.0});
834
835        let result = parser.parse(input).await;
836        assert!(result.is_err());
837
838        if let Err(EventError::ParseError { context, .. }) = result {
839            assert!(context.contains("Field 'amount' value too small"));
840        } else {
841            panic!("Expected ParseError");
842        }
843    }
844
845    #[tokio::test]
846    async fn test_json_parser_validation_numeric_range_above_max() {
847        let config =
848            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
849                .with_mapping("amount".to_string(), "amount".to_string())
850                .with_validation(ValidationConfig::default().with_range(
851                    "amount".to_string(),
852                    10.0,
853                    100.0,
854                ));
855
856        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
857        let input = json!({"amount": 150.0});
858
859        let result = parser.parse(input).await;
860        assert!(result.is_err());
861
862        if let Err(EventError::ParseError { context, .. }) = result {
863            assert!(context.contains("Field 'amount' value too large"));
864        } else {
865            panic!("Expected ParseError");
866        }
867    }
868
869    #[tokio::test]
870    async fn test_json_parser_validation_string_pattern_mismatch() {
871        let config =
872            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
873                .with_mapping("token".to_string(), "token".to_string())
874                .with_validation(
875                    ValidationConfig::default()
876                        .with_pattern("token".to_string(), "^USD[C|T]$".to_string()),
877                );
878
879        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
880        let input = json!({"token": "BTC"});
881
882        let result = parser.parse(input).await;
883        assert!(result.is_err());
884
885        if let Err(EventError::ParseError { context, .. }) = result {
886            assert!(context.contains("Field 'token' doesn't match pattern"));
887        } else {
888            panic!("Expected ParseError");
889        }
890    }
891
892    #[tokio::test]
893    async fn test_json_parser_validation_string_pattern_match() {
894        let config =
895            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
896                .with_mapping("token".to_string(), "token".to_string())
897                .with_validation(
898                    ValidationConfig::default()
899                        .with_pattern("token".to_string(), "^USD[C|T]$".to_string()),
900                );
901
902        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
903        let input = json!({"token": "USDC"});
904
905        let result = parser.parse(input).await;
906        assert!(result.is_ok());
907    }
908
909    #[tokio::test]
910    async fn test_json_parser_validation_invalid_regex_pattern() {
911        let config =
912            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
913                .with_mapping("token".to_string(), "token".to_string())
914                .with_validation(
915                    ValidationConfig::default()
916                        .with_pattern("token".to_string(), "[invalid".to_string()),
917                );
918
919        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
920        let input = json!({"token": "USDC"});
921
922        let result = parser.parse(input).await;
923        assert!(result.is_err());
924
925        if let Err(EventError::ParseError { context, .. }) = result {
926            assert!(context.contains("Invalid regex pattern for field 'token'"));
927        } else {
928            panic!("Expected ParseError");
929        }
930    }
931
932    #[tokio::test]
933    async fn test_json_parser_validation_non_object_input() {
934        let config =
935            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
936        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
937
938        let input = json!("not an object");
939        let result = parser.parse(input).await;
940        assert!(result.is_err());
941
942        if let Err(EventError::ParseError { context, .. }) = result {
943            assert!(context.contains("Data is not a JSON object"));
944        } else {
945            panic!("Expected ParseError");
946        }
947    }
948
949    #[tokio::test]
950    async fn test_json_parser_with_custom_id() {
951        let config =
952            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
953                .with_mapping("id".to_string(), "custom_id".to_string());
954
955        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
956        let input = json!({"custom_id": "my-custom-id"});
957
958        let events = parser.parse(input).await.unwrap();
959        assert_eq!(events.len(), 1);
960        assert_eq!(events[0].id(), "my-custom-id");
961    }
962
963    #[test]
964    fn test_json_parser_can_parse_valid() {
965        let config =
966            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
967                .with_mapping("field".to_string(), "nested.field".to_string());
968
969        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
970        let input = json!({"nested": {"field": "value"}});
971
972        assert!(parser.can_parse(&input));
973    }
974
975    #[test]
976    fn test_json_parser_can_parse_invalid() {
977        let config =
978            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
979                .with_mapping("field".to_string(), "nested.field".to_string());
980
981        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
982        let input = json!({"other": "value"});
983
984        assert!(!parser.can_parse(&input));
985    }
986
987    #[test]
988    fn test_json_parser_can_parse_empty_mappings() {
989        let config =
990            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string());
991        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
992        let input = json!({"any": "value"});
993
994        assert!(parser.can_parse(&input)); // No mappings to check
995    }
996
997    #[test]
998    fn test_json_parser_info() {
999        let config = ParsingConfig::new(
1000            "test-parser".to_string(),
1001            "2.0.0".to_string(),
1002            "json".to_string(),
1003        );
1004        let parser = JsonEventParser::new(config, EventKind::Contract, "test".to_string());
1005
1006        let info = parser.info();
1007        assert_eq!(info.name, "test-parser");
1008        assert_eq!(info.version, "2.0.0");
1009        assert!(info.supported_kinds.contains(&EventKind::Contract));
1010        assert!(info.supported_formats.contains(&"json".to_string()));
1011    }
1012
1013    #[test]
1014    fn test_multi_format_parser_new() {
1015        let parser = MultiFormatParser::new("binary".to_string());
1016        assert_eq!(parser.default_format, "binary");
1017        assert_eq!(parser.parsers.len(), 0);
1018    }
1019
1020    #[test]
1021    fn test_multi_format_parser_detect_format_json() {
1022        let parser = MultiFormatParser::new("binary".to_string());
1023
1024        assert_eq!(parser.detect_format(b"{\"key\": \"value\"}"), "json");
1025        assert_eq!(parser.detect_format(b"[1, 2, 3]"), "json");
1026    }
1027
1028    #[test]
1029    fn test_multi_format_parser_detect_format_xml() {
1030        let parser = MultiFormatParser::new("binary".to_string());
1031
1032        assert_eq!(parser.detect_format(b"<xml>content</xml>"), "xml");
1033    }
1034
1035    #[test]
1036    fn test_multi_format_parser_detect_format_default() {
1037        let parser = MultiFormatParser::new("custom".to_string());
1038
1039        assert_eq!(parser.detect_format(b"random binary data"), "custom");
1040    }
1041
1042    #[tokio::test]
1043    async fn test_multi_format_parser_parse_no_parser() {
1044        let parser = MultiFormatParser::new("unknown".to_string());
1045        let input = b"some data".to_vec();
1046
1047        let result = parser.parse(input).await;
1048        assert!(result.is_err());
1049
1050        if let Err(EventError::ParseError { context, .. }) = result {
1051            assert!(context.contains("No parser available for format: unknown"));
1052        } else {
1053            panic!("Expected ParseError");
1054        }
1055    }
1056
1057    #[test]
1058    fn test_multi_format_parser_can_parse_no_parser() {
1059        let parser = MultiFormatParser::new("unknown".to_string());
1060        let input = b"some data".to_vec();
1061
1062        assert!(!parser.can_parse(&input));
1063    }
1064
1065    #[test]
1066    fn test_multi_format_parser_info() {
1067        let parser = MultiFormatParser::new("default".to_string());
1068        let info = parser.info();
1069
1070        assert_eq!(info.name, "multi-format");
1071        assert_eq!(info.version, "1.0.0");
1072        // Should have multiple formats
1073        assert!(!info.supported_formats.is_empty());
1074    }
1075
1076    #[test]
1077    fn test_binary_parser_new() {
1078        let parser = BinaryEventParser::new(
1079            "bin-parser".to_string(),
1080            "1.5.0".to_string(),
1081            EventKind::Contract,
1082            "bin-source".to_string(),
1083        );
1084
1085        assert_eq!(parser.name, "bin-parser");
1086        assert_eq!(parser.version, "1.5.0");
1087        assert_eq!(parser.event_kind, EventKind::Contract);
1088        assert_eq!(parser.source_name, "bin-source");
1089    }
1090
1091    #[tokio::test]
1092    async fn test_binary_parser_parse_empty() {
1093        let parser = BinaryEventParser::new(
1094            "test".to_string(),
1095            "1.0.0".to_string(),
1096            EventKind::Transaction,
1097            "test".to_string(),
1098        );
1099
1100        let input = vec![];
1101        let events = parser.parse(input).await.unwrap();
1102
1103        assert_eq!(events.len(), 1);
1104        let event = &events[0];
1105        assert_eq!(event.kind(), &EventKind::Transaction);
1106        assert_eq!(event.source(), "test");
1107
1108        // Check data structure by downcasting to GenericEvent
1109        let generic_event = event
1110            .as_any()
1111            .downcast_ref::<crate::types::GenericEvent>()
1112            .unwrap();
1113        assert_eq!(generic_event.data["format"], "binary");
1114        assert_eq!(generic_event.data["hex"], "");
1115        assert_eq!(generic_event.data["length"], 0);
1116    }
1117
1118    #[tokio::test]
1119    async fn test_binary_parser_parse_with_data() {
1120        let parser = BinaryEventParser::new(
1121            "test".to_string(),
1122            "1.0.0".to_string(),
1123            EventKind::Transaction,
1124            "test".to_string(),
1125        );
1126
1127        let input = vec![0xde, 0xad, 0xbe, 0xef];
1128        let events = parser.parse(input.clone()).await.unwrap();
1129
1130        assert_eq!(events.len(), 1);
1131        let event = &events[0];
1132
1133        let generic_event = event
1134            .as_any()
1135            .downcast_ref::<crate::types::GenericEvent>()
1136            .unwrap();
1137        assert_eq!(generic_event.data["format"], "binary");
1138        assert_eq!(generic_event.data["hex"], "deadbeef");
1139        assert_eq!(generic_event.data["length"], 4);
1140        assert_eq!(
1141            generic_event.data["raw"],
1142            serde_json::Value::Array(vec![
1143                serde_json::Value::Number(serde_json::Number::from(0xde)),
1144                serde_json::Value::Number(serde_json::Number::from(0xad)),
1145                serde_json::Value::Number(serde_json::Number::from(0xbe)),
1146                serde_json::Value::Number(serde_json::Number::from(0xef)),
1147            ])
1148        );
1149    }
1150
1151    #[test]
1152    fn test_binary_parser_can_parse() {
1153        let parser = BinaryEventParser::new(
1154            "test".to_string(),
1155            "1.0.0".to_string(),
1156            EventKind::Transaction,
1157            "test".to_string(),
1158        );
1159
1160        assert!(parser.can_parse(&vec![]));
1161        assert!(parser.can_parse(&vec![1, 2, 3]));
1162        assert!(parser.can_parse(&vec![0; 1000]));
1163    }
1164
1165    #[test]
1166    fn test_binary_parser_info() {
1167        let parser = BinaryEventParser::new(
1168            "binary-test".to_string(),
1169            "2.1.0".to_string(),
1170            EventKind::External,
1171            "test".to_string(),
1172        );
1173
1174        let info = parser.info();
1175        assert_eq!(info.name, "binary-test");
1176        assert_eq!(info.version, "2.1.0");
1177        assert!(info.supported_kinds.contains(&EventKind::External));
1178        assert!(info.supported_formats.contains(&"binary".to_string()));
1179    }
1180
1181    #[test]
1182    fn test_validation_config_default() {
1183        let validation = ValidationConfig::default();
1184
1185        assert!(validation.required_fields.is_empty());
1186        assert!(validation.field_types.is_empty());
1187        assert!(validation.min_values.is_empty());
1188        assert!(validation.max_values.is_empty());
1189        assert!(validation.patterns.is_empty());
1190    }
1191
1192    #[test]
1193    fn test_validation_config_multiple_required() {
1194        let validation = ValidationConfig::default()
1195            .with_required("field1".to_string())
1196            .with_required("field2".to_string());
1197
1198        assert_eq!(validation.required_fields.len(), 2);
1199        assert!(validation.required_fields.contains(&"field1".to_string()));
1200        assert!(validation.required_fields.contains(&"field2".to_string()));
1201    }
1202
1203    #[test]
1204    fn test_validation_config_multiple_types() {
1205        let validation = ValidationConfig::default()
1206            .with_type("field1".to_string(), "string".to_string())
1207            .with_type("field2".to_string(), "number".to_string());
1208
1209        assert_eq!(validation.field_types.len(), 2);
1210        assert_eq!(
1211            validation.field_types.get("field1"),
1212            Some(&"string".to_string())
1213        );
1214        assert_eq!(
1215            validation.field_types.get("field2"),
1216            Some(&"number".to_string())
1217        );
1218    }
1219
1220    #[test]
1221    fn test_validation_config_range_sets_both_min_max() {
1222        let validation = ValidationConfig::default().with_range("amount".to_string(), 5.0, 10.0);
1223
1224        assert_eq!(validation.min_values.get("amount"), Some(&5.0));
1225        assert_eq!(validation.max_values.get("amount"), Some(&10.0));
1226    }
1227
1228    #[tokio::test]
1229    async fn test_json_parser_validation_non_numeric_range_field() {
1230        let config =
1231            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
1232                .with_mapping("field".to_string(), "field".to_string())
1233                .with_validation(ValidationConfig::default().with_range(
1234                    "field".to_string(),
1235                    0.0,
1236                    100.0,
1237                ));
1238
1239        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
1240        let input = json!({"field": "not a number"});
1241
1242        // Should not error for non-numeric fields when range validation is specified
1243        let result = parser.parse(input).await;
1244        assert!(result.is_ok());
1245    }
1246
1247    #[tokio::test]
1248    async fn test_json_parser_validation_non_string_pattern_field() {
1249        let config =
1250            ParsingConfig::new("test".to_string(), "1.0.0".to_string(), "json".to_string())
1251                .with_mapping("field".to_string(), "field".to_string())
1252                .with_validation(
1253                    ValidationConfig::default()
1254                        .with_pattern("field".to_string(), "pattern".to_string()),
1255                );
1256
1257        let parser = JsonEventParser::new(config, EventKind::Transaction, "test".to_string());
1258        let input = json!({"field": 123});
1259
1260        // Should not error for non-string fields when pattern validation is specified
1261        let result = parser.parse(input).await;
1262        assert!(result.is_ok());
1263    }
1264
1265    #[tokio::test]
1266    async fn test_multi_format_parser_with_parser() {
1267        let binary_parser = BinaryEventParser::new(
1268            "test-binary".to_string(),
1269            "1.0.0".to_string(),
1270            EventKind::Transaction,
1271            "test".to_string(),
1272        );
1273
1274        let multi_parser = MultiFormatParser::new("default".to_string())
1275            .with_parser("binary".to_string(), binary_parser);
1276
1277        // Test parsing with the added parser
1278        let input = b"random binary data".to_vec(); // Will be detected as default format
1279        let result = multi_parser.parse(input).await;
1280
1281        // Should fail because "default" format parser is not registered, only "binary" is
1282        assert!(result.is_err());
1283
1284        // Test with JSON format detection and parsing
1285        let json_input = b"{\"test\": \"data\"}".to_vec();
1286        let result = multi_parser.parse(json_input).await;
1287        // Should fail because no JSON parser is registered
1288        assert!(result.is_err());
1289    }
1290
1291    #[tokio::test]
1292    async fn test_multi_format_parser_with_json_format() {
1293        let binary_parser = BinaryEventParser::new(
1294            "test-binary".to_string(),
1295            "1.0.0".to_string(),
1296            EventKind::Transaction,
1297            "test".to_string(),
1298        );
1299
1300        let multi_parser = MultiFormatParser::new("binary".to_string())
1301            .with_parser("binary".to_string(), binary_parser);
1302
1303        // Test with data that will be detected as JSON but no JSON parser is registered
1304        let json_input = b"{\"test\": \"data\"}".to_vec();
1305        let result = multi_parser.parse(json_input).await;
1306        assert!(result.is_err());
1307
1308        // Test with data that will use default format (binary)
1309        let binary_input = b"some binary data".to_vec();
1310        let result = multi_parser.parse(binary_input).await;
1311        assert!(result.is_ok());
1312
1313        let events = result.unwrap();
1314        assert_eq!(events.len(), 1);
1315    }
1316
1317    #[test]
1318    fn test_multi_format_parser_can_parse_with_registered_parser() {
1319        let binary_parser = BinaryEventParser::new(
1320            "test-binary".to_string(),
1321            "1.0.0".to_string(),
1322            EventKind::Transaction,
1323            "test".to_string(),
1324        );
1325
1326        let multi_parser = MultiFormatParser::new("binary".to_string())
1327            .with_parser("binary".to_string(), binary_parser);
1328
1329        // Test data that defaults to binary format
1330        let input = b"random data".to_vec();
1331        assert!(multi_parser.can_parse(&input));
1332
1333        // Test data that would be detected as JSON but no JSON parser
1334        let json_input = b"{\"test\": \"data\"}".to_vec();
1335        assert!(!multi_parser.can_parse(&json_input));
1336    }
1337}