1use crate::{DsonOperation, OperationValue, StreamGenerator};
9use ahash::{AHashMap, AHashSet};
10use fionn_core::Result;
11use fionn_core::path::{ParsedPath, PathCache, PathComponentRange};
12use fionn_tape::DsonTape;
13use simd_json::value::tape::Node;
14use smallvec::SmallVec;
15use std::collections::VecDeque;
16use std::sync::Arc;
17
18type FastHashMap<K, V> = AHashMap<K, V>;
20type FastHashSet<T> = AHashSet<T>;
21type PathStack = SmallVec<[String; 8]>;
23
24#[derive(Debug, Clone)]
28pub struct SchemaFilter {
29 paths: Arc<[String]>,
31 compiled_patterns: Arc<[regex::Regex]>,
33}
34
35impl SchemaFilter {
36 #[must_use]
38 #[inline]
39 pub fn paths(&self) -> &[String] {
40 &self.paths
41 }
42}
43
44impl SchemaFilter {
45 pub fn new(paths: Vec<String>) -> Result<Self> {
50 let mut compiled_patterns = Vec::with_capacity(paths.len());
51
52 for path in &paths {
53 let regex_pattern = Self::json_path_to_regex(path);
55 let regex = regex::Regex::new(®ex_pattern).map_err(|e| {
56 fionn_core::DsonError::InvalidOperation(format!(
57 "Invalid JSON-path pattern '{path}': {e}"
58 ))
59 })?;
60 compiled_patterns.push(regex);
61 }
62
63 let paths: Arc<[String]> = paths.into();
65 let compiled_patterns: Arc<[regex::Regex]> = compiled_patterns.into();
66
67 Ok(Self {
68 paths,
69 compiled_patterns,
70 })
71 }
72
73 #[inline]
75 #[must_use]
76 pub fn matches(&self, json_path: &str) -> bool {
77 self.compiled_patterns
78 .iter()
79 .any(|pattern| pattern.is_match(json_path))
80 }
81
82 fn json_path_to_regex(pattern: &str) -> String {
84 let mut regex = "^".to_string();
86
87 for part in pattern.split('.') {
88 if part == "*" {
89 regex.push_str(r"[^\.]*");
90 } else if part.starts_with('[') && part.ends_with(']') {
91 if part == "[*]" {
92 regex.push_str(r"\[\d+\]");
93 } else {
94 regex.push_str(®ex::escape(part));
96 }
97 } else {
98 regex.push_str(®ex::escape(part));
99 }
100 regex.push_str(r"\.?");
101 }
102
103 if regex.ends_with(r"\.?") {
105 regex.truncate(regex.len() - 3);
106 }
107
108 regex.push('$');
109 regex
110 }
111
112 #[must_use]
114 pub fn get_matching_paths(&self, root_path: &str) -> Vec<String> {
115 self.paths
116 .iter()
117 .filter(|pattern| Self::path_matches_pattern(root_path, pattern))
118 .cloned()
119 .collect()
120 }
121
122 #[inline]
129 fn path_matches_pattern(path: &str, pattern: &str) -> bool {
130 if path == pattern {
132 return true;
133 }
134
135 if pattern.contains("[*]") {
137 let parts: Vec<&str> = pattern.split("[*]").collect();
139 if parts.len() == 2 {
140 let prefix = parts[0];
141 let suffix = parts[1];
142
143 if let Some(remaining) = path.strip_prefix(prefix) {
145 if remaining.starts_with('[')
147 && let Some(bracket_end) = remaining.find(']')
148 {
149 let after_bracket = &remaining[bracket_end + 1..];
150 let index_part = &remaining[1..bracket_end];
152 if index_part.chars().all(|c| c.is_ascii_digit()) {
153 if suffix.is_empty() {
154 return after_bracket.is_empty() || after_bracket.starts_with('.');
155 }
156 return after_bracket == suffix
157 || after_bracket.starts_with(&format!("{suffix}."));
158 }
159 }
160 }
161 }
162 return false;
163 }
164
165 if pattern.contains("**") {
167 let prefix = pattern.replace("**", "");
168 return path.starts_with(&prefix);
169 }
170
171 if pattern.contains('*') {
173 let parts: Vec<&str> = pattern.split('*').collect();
174 if parts.len() == 2 {
175 return path.starts_with(parts[0]) && path.ends_with(parts[1]);
176 }
177 }
178
179 if path.starts_with(pattern) {
181 let next_char = path.chars().nth(pattern.len());
182 return next_char == Some('.') || next_char.is_none();
183 }
184
185 false
186 }
187}
188
189#[derive(Debug, Clone)]
191pub struct JsonPathContext {
192 current_path: PathStack,
194 active_paths: FastHashSet<String>,
196 depth: usize,
198}
199
200impl JsonPathContext {
201 #[inline]
203 #[must_use]
204 pub fn new(active_paths: FastHashSet<String>) -> Self {
205 Self {
206 current_path: PathStack::new(),
207 active_paths,
208 depth: 0,
209 }
210 }
211
212 #[inline]
214 pub fn enter_scope(&mut self, segment: &str) {
215 self.current_path.push(segment.to_string());
216 self.depth += 1;
217 }
218
219 #[inline]
221 pub fn exit_scope(&mut self) {
222 if !self.current_path.is_empty() {
223 self.current_path.pop();
224 self.depth = self.depth.saturating_sub(1);
225 }
226 }
227
228 #[inline]
230 #[must_use]
231 pub fn current_path(&self) -> String {
232 self.current_path.join(".")
233 }
234
235 #[inline]
237 #[must_use]
238 pub fn should_process(&self) -> bool {
239 let current = self.current_path();
240 self.active_paths
241 .iter()
242 .any(|active| active.starts_with(¤t) || current.starts_with(active))
243 }
244
245 #[inline]
247 #[must_use]
248 pub fn is_path_relevant(&self, path: &str) -> bool {
249 self.active_paths.contains(path)
250 || self
251 .active_paths
252 .iter()
253 .any(|active| path.starts_with(active))
254 }
255}
256
257#[derive(Debug, Clone, Copy, PartialEq, Eq)]
259pub enum ProcessingMode {
260 Fast,
262 Balanced,
264 MemoryEfficient,
266}
267
268pub struct BlackBoxProcessor {
270 tape: Option<DsonTape>,
272 input_filter: Option<SchemaFilter>,
274 output_filter: Option<SchemaFilter>,
276 context: JsonPathContext,
278 modifications: FastHashMap<String, OperationValue>,
280 deletions: FastHashSet<String>,
282 stream_buffer: VecDeque<serde_json::Value>,
284 path_cache: PathCache,
286}
287
288impl BlackBoxProcessor {
289 #[must_use]
291 pub fn new(input_schema: Vec<String>, output_schema: Vec<String>) -> Self {
292 let input_filter = if input_schema.is_empty() {
293 None
294 } else {
295 SchemaFilter::new(input_schema).ok()
296 };
297
298 let output_filter = if output_schema.is_empty() {
299 None
300 } else {
301 SchemaFilter::new(output_schema).ok()
302 };
303
304 let mut active_paths = FastHashSet::default();
306 if let Some(filter) = &input_filter {
307 active_paths.extend(filter.paths.iter().cloned());
308 }
309 if let Some(filter) = &output_filter {
310 active_paths.extend(filter.paths.iter().cloned());
311 }
312
313 Self {
314 tape: None,
315 input_filter,
316 output_filter,
317 context: JsonPathContext::new(active_paths),
318 modifications: FastHashMap::default(),
319 deletions: FastHashSet::default(),
320 stream_buffer: VecDeque::new(),
321 path_cache: PathCache::new(),
322 }
323 }
324
325 #[must_use]
327 pub fn new_unfiltered() -> Self {
328 Self {
329 tape: None,
330 input_filter: None,
331 output_filter: None,
332 context: JsonPathContext::new(FastHashSet::default()),
333 modifications: FastHashMap::default(),
334 deletions: FastHashSet::default(),
335 stream_buffer: VecDeque::new(),
336 path_cache: PathCache::new(),
337 }
338 }
339
340 pub fn process(&mut self, input: &str) -> Result<String> {
345 self.modifications.clear();
347 self.deletions.clear();
348 self.stream_buffer.clear();
349
350 let full_tape = DsonTape::parse(input)?;
352
353 if let Some(filter) = &self.input_filter {
355 let schema_set: std::collections::HashSet<String> =
357 filter.paths().iter().cloned().collect();
358
359 self.tape = Some(full_tape.filter_by_schema(&schema_set)?);
361 } else {
362 self.tape = Some(full_tape);
363 }
364
365 self.generate_output()
367 }
368
369 pub fn apply_operations(&mut self, operations: &[DsonOperation]) -> Result<()> {
374 for operation in operations {
375 self.apply_operation(operation)?;
376 }
377 Ok(())
378 }
379
380 pub fn apply_operations_canonical(&mut self, operations: &[DsonOperation]) -> Result<()> {
385 self.apply_operations(operations)
387 }
388
389 pub fn process_with_operations(
394 &mut self,
395 input: &str,
396 operations: &[DsonOperation],
397 ) -> Result<String> {
398 self.process_with_operations_internal(input, operations, false)
399 }
400
401 pub fn process_with_operations_canonical(
406 &mut self,
407 input: &str,
408 operations: &[DsonOperation],
409 ) -> Result<String> {
410 self.process_with_operations_internal(input, operations, true)
411 }
412
413 fn process_with_operations_internal(
415 &mut self,
416 input: &str,
417 operations: &[DsonOperation],
418 use_canonical: bool,
419 ) -> Result<String> {
420 self.tape = Some(DsonTape::parse(input)?);
422
423 self.modifications.clear();
425 self.deletions.clear();
426
427 if use_canonical {
429 self.apply_operations_canonical(operations)?;
430 } else {
431 self.apply_operations(operations)?;
432 }
433
434 self.generate_output()
436 }
437
438 #[inline]
443 pub fn read_field(&self, field_path: &str) -> Result<Option<Node<'static>>> {
444 self.tape.as_ref().map_or(Ok(None), |tape| {
445 tape.resolve_path(field_path)?.map_or(Ok(None), |index| {
447 let nodes = tape.nodes();
448 if index < nodes.len() {
449 Ok(Some(nodes[index]))
450 } else {
451 Ok(None)
452 }
453 })
454 })
455 }
456
457 #[inline]
464 pub fn read_field_value(&self, field_path: &str) -> Result<Option<OperationValue>> {
465 if let Some(value) = self.modifications.get(field_path) {
467 return Ok(Some(value.clone()));
468 }
469
470 self.read_field(field_path)?.map_or(Ok(None), |node| {
472 let value = match node {
473 Node::String(s) => OperationValue::StringRef(s.to_string()),
474 Node::Static(simd_json::StaticNode::Bool(b)) => OperationValue::BoolRef(b),
475 Node::Static(simd_json::StaticNode::Null) => OperationValue::Null,
476 Node::Static(simd_json::StaticNode::I64(n)) => {
477 OperationValue::NumberRef(n.to_string())
478 }
479 Node::Static(simd_json::StaticNode::U64(n)) => {
480 OperationValue::NumberRef(n.to_string())
481 }
482 Node::Static(simd_json::StaticNode::F64(n)) => {
483 OperationValue::NumberRef(n.to_string())
484 }
485 Node::Object { len, .. } => OperationValue::ObjectRef { start: 0, end: len },
486 Node::Array { len, .. } => OperationValue::ArrayRef { start: 0, end: len },
487 };
488 Ok(Some(value))
489 })
490 }
491
492 pub fn write_field(&mut self, field_path: &str, value: Node<'static>) -> Result<()> {
497 let op_value = match value {
499 Node::String(s) => OperationValue::StringRef(s.to_string()),
500 Node::Static(simd_json::StaticNode::Bool(b)) => OperationValue::BoolRef(b),
501 Node::Static(simd_json::StaticNode::Null) => OperationValue::Null,
502 Node::Static(simd_json::StaticNode::I64(n)) => OperationValue::NumberRef(n.to_string()),
503 Node::Static(simd_json::StaticNode::U64(n)) => OperationValue::NumberRef(n.to_string()),
504 Node::Static(simd_json::StaticNode::F64(n)) => OperationValue::NumberRef(n.to_string()),
505 Node::Object { .. } => OperationValue::ObjectRef { start: 0, end: 0 },
506 Node::Array { .. } => OperationValue::ArrayRef { start: 0, end: 0 },
507 };
508 self.modifications.insert(field_path.to_string(), op_value);
509 Ok(())
510 }
511
512 pub fn advance_field(&self) -> Result<bool> {
517 self.tape.as_ref().map_or(Ok(false), |tape| {
519 let nodes = tape.nodes();
522 Ok(nodes.len() > 1) })
524 }
525
526 pub fn push_record(&mut self, record: Node<'static>) -> Result<()> {
531 let _op_value = match record {
534 Node::String(s) => OperationValue::StringRef(s.to_string()),
535 Node::Static(simd_json::StaticNode::Bool(b)) => OperationValue::BoolRef(b),
536 Node::Static(simd_json::StaticNode::I64(n)) => OperationValue::NumberRef(n.to_string()),
537 Node::Static(simd_json::StaticNode::U64(n)) => OperationValue::NumberRef(n.to_string()),
538 Node::Static(simd_json::StaticNode::F64(n)) => OperationValue::NumberRef(n.to_string()),
539 Node::Static(simd_json::StaticNode::Null)
540 | Node::Object { .. }
541 | Node::Array { .. } => OperationValue::Null,
542 };
543
544 self.stream_buffer
546 .push_back(serde_json::json!({"_pushed": true}));
547 Ok(())
548 }
549
550 pub fn advance_array_index(&self) -> Result<bool> {
555 self.tape.as_ref().map_or(Ok(false), |tape| {
557 let nodes = tape.nodes();
558 Ok(nodes.len() > 1) })
560 }
561
562 #[must_use]
564 pub fn input_schema(&self) -> Vec<String> {
565 self.input_filter
566 .as_ref()
567 .map(|f| f.paths.to_vec())
568 .unwrap_or_default()
569 }
570
571 #[must_use]
573 pub fn output_schema(&self) -> Vec<String> {
574 self.output_filter
575 .as_ref()
576 .map(|f| f.paths.to_vec())
577 .unwrap_or_default()
578 }
579
580 pub fn apply_operation(&mut self, operation: &DsonOperation) -> Result<()> {
585 match operation {
586 DsonOperation::FieldAdd { path, value }
587 | DsonOperation::FieldModify { path, value }
588 | DsonOperation::MergeField { path, value, .. } => {
589 self.apply_field_modify(path, value);
590 }
591 DsonOperation::FieldDelete { path } => {
592 self.apply_field_delete(path);
593 }
594 DsonOperation::ArrayInsert { path, index, value } => {
595 self.apply_array_insert(path, *index, value);
596 }
597 DsonOperation::ArrayRemove { path, index } => {
598 self.apply_array_remove(path, *index);
599 }
600 DsonOperation::ArrayReplace { path, index, value } => {
601 self.apply_array_replace(path, *index, value);
602 }
603 DsonOperation::ArrayBuild { path, elements } => {
604 self.apply_array_build(path, elements);
605 }
606 DsonOperation::ArrayFilter { path, predicate } => {
607 self.apply_array_filter(path, predicate);
608 }
609 DsonOperation::ArrayMap { path, transform } => {
610 self.apply_array_map(path, transform);
611 }
612 DsonOperation::ArrayReduce {
613 path,
614 initial,
615 reducer,
616 } => {
617 self.apply_array_reduce(path, initial, reducer);
618 }
619 DsonOperation::BatchExecute { operations } => {
620 self.apply_batch_execute(operations)?;
621 }
622 DsonOperation::CheckPresence { .. }
625 | DsonOperation::CheckAbsence { .. }
626 | DsonOperation::CheckNull { .. }
627 | DsonOperation::CheckNotNull { .. }
628 | DsonOperation::ConflictResolve { .. }
629 | DsonOperation::ObjectStart { .. }
630 | DsonOperation::ObjectEnd { .. }
631 | DsonOperation::ArrayStart { .. }
632 | DsonOperation::ArrayEnd { .. } => {}
633 DsonOperation::StreamBuild { path, generator } => {
635 self.apply_stream_build(path, generator);
636 }
637 DsonOperation::StreamFilter { path, predicate } => {
638 self.apply_stream_filter(path, predicate);
639 }
640 DsonOperation::StreamMap { path, transform } => {
641 self.apply_stream_map(path, transform);
642 }
643 DsonOperation::StreamEmit { path, batch_size } => {
644 self.apply_stream_emit(path, *batch_size);
645 }
646 }
647 Ok(())
648 }
649
650 fn apply_field_modify(&mut self, path: &str, value: &OperationValue) {
652 self.modifications.insert(path.to_string(), value.clone());
654 self.deletions.remove(path);
656 }
657
658 fn apply_field_delete(&mut self, path: &str) {
660 self.deletions.insert(path.to_string());
662 self.modifications.remove(path);
664 }
665
666 fn apply_array_insert(&mut self, path: &str, index: usize, value: &OperationValue) {
668 let array_path = format!("{path}[{index}]");
671 self.modifications.insert(array_path, value.clone());
672 }
673
674 fn apply_array_remove(&mut self, path: &str, index: usize) {
676 let array_path = format!("{path}[{index}]");
678 self.deletions.insert(array_path);
679 }
680
681 fn apply_array_replace(&mut self, path: &str, index: usize, value: &OperationValue) {
683 let array_path = format!("{path}[{index}]");
685 self.modifications.insert(array_path, value.clone());
686 }
687
688 fn apply_array_build(&mut self, path: &str, elements: &[OperationValue]) {
690 let array_value = OperationValue::ArrayRef {
692 start: 0, end: elements.len(),
694 };
695 self.modifications.insert(path.to_string(), array_value);
696 }
697
698 fn apply_array_filter(&mut self, path: &str, predicate: &crate::FilterPredicate) {
700 let filter_path = format!("{path}.filter");
703 let filter_value = match predicate {
704 crate::FilterPredicate::Even => OperationValue::StringRef("even".to_string()),
705 crate::FilterPredicate::Odd => OperationValue::StringRef("odd".to_string()),
706 crate::FilterPredicate::EveryNth(n) => OperationValue::NumberRef(n.to_string()),
707 _ => OperationValue::StringRef("custom_filter".to_string()),
708 };
709 self.modifications.insert(filter_path, filter_value);
710 }
711
712 fn apply_array_map(&mut self, path: &str, transform: &crate::TransformFunction) {
714 let map_path = format!("{path}.map");
716 let map_value = match transform {
717 crate::TransformFunction::Add(n) => OperationValue::NumberRef(n.to_string()),
718 crate::TransformFunction::Multiply(n) => OperationValue::NumberRef(format!("*{n}")),
719 crate::TransformFunction::ToUppercase => {
720 OperationValue::StringRef("uppercase".to_string())
721 }
722 _ => OperationValue::StringRef("custom_transform".to_string()),
723 };
724 self.modifications.insert(map_path, map_value);
725 }
726
727 fn apply_array_reduce(
729 &mut self,
730 path: &str,
731 _initial: &OperationValue,
732 reducer: &crate::ReduceFunction,
733 ) {
734 let reduce_path = format!("{path}.reduce");
736 let reduce_value = match reducer {
737 crate::ReduceFunction::Sum => OperationValue::StringRef("sum".to_string()),
738 crate::ReduceFunction::Count => OperationValue::StringRef("count".to_string()),
739 crate::ReduceFunction::Min => OperationValue::StringRef("min".to_string()),
740 crate::ReduceFunction::Max => OperationValue::StringRef("max".to_string()),
741 _ => OperationValue::StringRef("custom_reduce".to_string()),
742 };
743 self.modifications.insert(reduce_path, reduce_value);
744 }
745
746 fn apply_batch_execute(&mut self, operations: &[DsonOperation]) -> Result<()> {
748 for operation in operations {
749 self.apply_operation(operation)?;
750 }
751 Ok(())
752 }
753
754 fn apply_stream_build(&mut self, path: &str, generator: &crate::StreamGenerator) {
756 let stream_path = format!("{path}.stream_build");
758 let generator_value = match generator {
759 StreamGenerator::Range { start, end, step } => {
760 OperationValue::StringRef(format!("range:{start},{end},{step}"))
761 }
762 StreamGenerator::Repeat(_value, count) => {
763 OperationValue::StringRef(format!("repeat:{count}"))
764 }
765 StreamGenerator::Fibonacci(count) => {
766 OperationValue::StringRef(format!("fibonacci:{count}"))
767 }
768 StreamGenerator::Custom(desc) => OperationValue::StringRef(format!("custom:{desc}")),
769 };
770 self.modifications.insert(stream_path, generator_value);
771 }
772
773 fn apply_stream_filter(&mut self, path: &str, predicate: &crate::FilterPredicate) {
775 let filter_path = format!("{path}.stream_filter");
777 let predicate_value = match predicate {
778 crate::FilterPredicate::Even => OperationValue::StringRef("even".to_string()),
779 crate::FilterPredicate::Odd => OperationValue::StringRef("odd".to_string()),
780 crate::FilterPredicate::EveryNth(n) => OperationValue::NumberRef(n.to_string()),
781 crate::FilterPredicate::GreaterThan(val) => OperationValue::NumberRef(val.to_string()),
782 _ => OperationValue::StringRef("custom_filter".to_string()),
783 };
784 self.modifications.insert(filter_path, predicate_value);
785 }
786
787 fn apply_stream_map(&mut self, path: &str, transform: &crate::TransformFunction) {
789 let map_path = format!("{path}.stream_map");
791 let transform_value = match transform {
792 crate::TransformFunction::Add(n) => OperationValue::NumberRef(n.to_string()),
793 crate::TransformFunction::Multiply(n) => OperationValue::NumberRef(format!("*{n}")),
794 crate::TransformFunction::ToUppercase => {
795 OperationValue::StringRef("uppercase".to_string())
796 }
797 _ => OperationValue::StringRef("custom_transform".to_string()),
798 };
799 self.modifications.insert(map_path, transform_value);
800 }
801
802 fn apply_stream_emit(&mut self, path: &str, batch_size: usize) {
804 let emit_path = format!("{path}.stream_emit");
806 let emit_value = OperationValue::NumberRef(batch_size.to_string());
807 self.modifications.insert(emit_path, emit_value);
808 }
809
810 pub fn generate_output(&self) -> Result<String> {
815 self.tape.as_ref().map_or_else(
816 || Ok("{}".to_string()),
817 |tape| self.generate_output_from_tape(tape),
818 )
819 }
820
821 fn parse_with_schema_filtering(&mut self, input: &str, filter: &SchemaFilter) -> Result<()> {
823 let full_tape = DsonTape::parse(input)?;
825
826 let schema_set: std::collections::HashSet<String> =
828 filter.paths().iter().cloned().collect();
829 let filtered_tape = full_tape.filter_by_schema(&schema_set)?;
830
831 self.tape = Some(filtered_tape);
832 Ok(())
833 }
834
835 fn generate_output_from_tape(&self, tape: &DsonTape) -> Result<String> {
837 let mut result = tape.serialize_with_modifications(&self.modifications, &self.deletions)?;
839
840 if let Some(filter) = &self.output_filter {
842 let base_value: serde_json::Value = serde_json::from_str(&result)
843 .map_err(|e| fionn_core::DsonError::ParseError(format!("JSON parse error: {e}")))?;
844
845 let filtered_value = self.apply_output_filtering(&base_value, filter);
846
847 result = serde_json::to_string(&filtered_value).map_err(|e| {
848 fionn_core::DsonError::SerializationError(format!("JSON write error: {e}"))
849 })?;
850 }
851
852 Ok(result)
853 }
854
855 fn apply_output_filtering(
857 &self,
858 value: &serde_json::Value,
859 filter: &SchemaFilter,
860 ) -> serde_json::Value {
861 match value {
862 serde_json::Value::Object(obj) => {
863 let mut filtered_obj = serde_json::Map::new();
864
865 for (key, val) in obj {
866 let path = if self.context.current_path.is_empty() {
867 key.clone()
868 } else {
869 format!("{}.{}", self.context.current_path(), key)
870 };
871
872 if filter.matches(&path) {
873 let filtered_val = self.apply_output_filtering(val, filter);
874 filtered_obj.insert(key.clone(), filtered_val);
875 }
876 }
877
878 serde_json::Value::Object(filtered_obj)
879 }
880 serde_json::Value::Array(arr) => {
881 let mut filtered_arr = Vec::new();
882
883 for (index, val) in arr.iter().enumerate() {
884 let path = format!("{}[{}]", self.context.current_path(), index);
885
886 if filter.matches(&path) {
887 let filtered_val = self.apply_output_filtering(val, filter);
888 filtered_arr.push(filtered_val);
889 }
890 }
891
892 serde_json::Value::Array(filtered_arr)
893 }
894 _ => value.clone(),
896 }
897 }
898
899 #[must_use]
901 pub const fn modifications(&self) -> &FastHashMap<String, OperationValue> {
902 &self.modifications
903 }
904
905 #[must_use]
907 pub const fn deletions(&self) -> &FastHashSet<String> {
908 &self.deletions
909 }
910
911 #[must_use]
913 pub const fn determine_processing_mode(
914 &self,
915 document_size: usize,
916 operation_count: usize,
917 ) -> ProcessingMode {
918 if document_size < 10_000 && operation_count < 10 {
920 ProcessingMode::Fast
921 }
922 else if document_size > 1_000_000 || operation_count > 100 {
924 ProcessingMode::MemoryEfficient
925 }
926 else {
928 ProcessingMode::Balanced
929 }
930 }
931
932 pub fn process_adaptive(
937 &mut self,
938 input: &str,
939 operations: &[DsonOperation],
940 ) -> Result<String> {
941 let mode = self.determine_processing_mode(input.len(), operations.len());
942
943 match mode {
944 ProcessingMode::Fast => {
945 self.process_fast_path(input, operations)
947 }
948 ProcessingMode::Balanced => {
949 self.process_balanced(input, operations)
951 }
952 ProcessingMode::MemoryEfficient => {
953 self.process_memory_efficient(input, operations)
955 }
956 }
957 }
958
959 fn process_fast_path(&mut self, input: &str, operations: &[DsonOperation]) -> Result<String> {
961 let mut value: serde_json::Value = serde_json::from_str(input)
963 .map_err(|e| fionn_core::DsonError::ParseError(format!("JSON parse error: {e}")))?;
964
965 for operation in operations {
967 self.apply_operation_to_value(&mut value, operation)?;
968 }
969
970 serde_json::to_string(&value).map_err(|e| {
972 fionn_core::DsonError::SerializationError(format!("JSON write error: {e}"))
973 })
974 }
975
976 fn process_balanced(&mut self, input: &str, operations: &[DsonOperation]) -> Result<String> {
978 self.process_with_operations_canonical(input, operations)
980 }
981
982 fn process_memory_efficient(
984 &mut self,
985 input: &str,
986 operations: &[DsonOperation],
987 ) -> Result<String> {
988 if let Some(filter) = &self.input_filter {
990 let filter = filter.clone();
992 self.parse_with_schema_filtering(input, &filter)?;
993 } else {
994 self.tape = Some(DsonTape::parse(input)?);
995 }
996
997 self.apply_operations_canonical(operations)?;
999
1000 self.generate_output()
1002 }
1003
1004 fn apply_operation_to_value(
1006 &mut self,
1007 value: &mut serde_json::Value,
1008 operation: &DsonOperation,
1009 ) -> Result<()> {
1010 match operation {
1011 DsonOperation::FieldAdd {
1012 path,
1013 value: op_value,
1014 }
1015 | DsonOperation::FieldModify {
1016 path,
1017 value: op_value,
1018 } => {
1019 let json_value = Self::operation_value_to_json(op_value);
1020 let parsed = self.path_cache.get_or_parse(path);
1021 Self::set_path_in_value_parsed(value, &parsed, &json_value);
1022 Ok(())
1023 }
1024 DsonOperation::FieldDelete { path } => {
1025 let parsed = self.path_cache.get_or_parse(path);
1026 Self::delete_path_from_value_parsed(value, &parsed);
1027 Ok(())
1028 }
1029 _ => {
1031 let json_str = serde_json::to_string(value).map_err(|e| {
1033 fionn_core::DsonError::SerializationError(format!("JSON serialize error: {e}"))
1034 })?;
1035
1036 self.tape = Some(DsonTape::parse(&json_str)?);
1037 self.apply_operation(operation)?;
1038 *value = serde_json::from_str(&self.generate_output()?).map_err(|e| {
1039 fionn_core::DsonError::ParseError(format!("JSON parse error: {e}"))
1040 })?;
1041 Ok(())
1042 }
1043 }
1044 }
1045
1046 pub fn apply_operation_to_value_cached(
1051 &mut self,
1052 value: &mut serde_json::Value,
1053 operation: &DsonOperation,
1054 ) -> Result<()> {
1055 self.apply_operation_to_value(value, operation)
1056 }
1057
1058 pub fn apply_operation_to_value_parsed(
1063 &mut self,
1064 value: &mut serde_json::Value,
1065 operation: &DsonOperation,
1066 parsed: &ParsedPath,
1067 ) -> Result<()> {
1068 match operation {
1069 DsonOperation::FieldAdd {
1070 value: op_value, ..
1071 }
1072 | DsonOperation::FieldModify {
1073 value: op_value, ..
1074 } => {
1075 let json_value = Self::operation_value_to_json(op_value);
1076 Self::set_path_in_value_parsed(value, parsed, &json_value);
1077 Ok(())
1078 }
1079 DsonOperation::FieldDelete { .. } => {
1080 Self::delete_path_from_value_parsed(value, parsed);
1081 Ok(())
1082 }
1083 _ => self.apply_operation_to_value(value, operation),
1084 }
1085 }
1086
1087 fn set_path_in_value_parsed(
1089 value: &mut serde_json::Value,
1090 parsed: &ParsedPath,
1091 new_value: &serde_json::Value,
1092 ) {
1093 Self::set_value_recursive_parsed(value, parsed.path(), parsed.components(), 0, new_value);
1094 }
1095
1096 fn set_value_recursive_parsed(
1098 value: &mut serde_json::Value,
1099 path: &str,
1100 parts: &[PathComponentRange],
1101 index: usize,
1102 new_value: &serde_json::Value,
1103 ) {
1104 if index >= parts.len() {
1105 *value = new_value.clone();
1106 return;
1107 }
1108
1109 let part = &parts[index];
1110
1111 match part {
1112 PathComponentRange::Field(range) => {
1113 let field = &path[range.clone()];
1114 if let serde_json::Value::Object(obj) = value {
1115 if index == parts.len() - 1 {
1116 obj.insert(field.to_string(), new_value.clone());
1117 } else {
1118 if !obj.contains_key(field) {
1119 obj.insert(
1120 field.to_string(),
1121 serde_json::Value::Object(serde_json::Map::new()),
1122 );
1123 }
1124 if let Some(child) = obj.get_mut(field) {
1125 Self::set_value_recursive_parsed(
1126 child,
1127 path,
1128 parts,
1129 index + 1,
1130 new_value,
1131 );
1132 }
1133 }
1134 } else if index == parts.len() - 1 {
1135 let mut obj = serde_json::Map::new();
1136 obj.insert(field.to_string(), new_value.clone());
1137 *value = serde_json::Value::Object(obj);
1138 }
1139 }
1140 PathComponentRange::ArrayIndex(idx) => {
1141 if let serde_json::Value::Array(arr) = value {
1142 if index == parts.len() - 1 {
1143 while arr.len() <= *idx {
1144 arr.push(serde_json::Value::Null);
1145 }
1146 arr[*idx] = new_value.clone();
1147 } else if *idx < arr.len() {
1148 Self::set_value_recursive_parsed(
1149 &mut arr[*idx],
1150 path,
1151 parts,
1152 index + 1,
1153 new_value,
1154 );
1155 }
1156 } else if index == parts.len() - 1 {
1157 let mut arr = Vec::new();
1158 while arr.len() <= *idx {
1159 arr.push(serde_json::Value::Null);
1160 }
1161 arr[*idx] = new_value.clone();
1162 *value = serde_json::Value::Array(arr);
1163 }
1164 }
1165 }
1166 }
1167
1168 fn operation_value_to_json(op_value: &crate::OperationValue) -> serde_json::Value {
1170 match op_value {
1171 crate::OperationValue::StringRef(s) => serde_json::Value::String(s.clone()),
1172 crate::OperationValue::NumberRef(n) => n.parse::<i64>().map_or_else(
1173 |_| {
1174 n.parse::<f64>()
1175 .ok()
1176 .and_then(serde_json::Number::from_f64)
1177 .map_or_else(
1178 || serde_json::Value::String(n.clone()),
1179 serde_json::Value::Number,
1180 )
1181 },
1182 |num| serde_json::Value::Number(num.into()),
1183 ),
1184 crate::OperationValue::BoolRef(b) => serde_json::Value::Bool(*b),
1185 crate::OperationValue::Null => serde_json::Value::Null,
1186 crate::OperationValue::ObjectRef { .. } => {
1190 serde_json::Value::Object(serde_json::Map::new())
1191 }
1192 crate::OperationValue::ArrayRef { .. } => serde_json::Value::Array(Vec::new()),
1193 }
1194 }
1195
1196 fn delete_path_from_value_parsed(value: &mut serde_json::Value, parsed: &ParsedPath) {
1198 Self::delete_value_recursive_parsed(value, parsed.path(), parsed.components(), 0);
1199 }
1200
1201 fn delete_value_recursive_parsed(
1203 value: &mut serde_json::Value,
1204 path: &str,
1205 parts: &[PathComponentRange],
1206 index: usize,
1207 ) {
1208 if index >= parts.len() {
1209 return;
1210 }
1211
1212 let part = &parts[index];
1213
1214 match (value, part) {
1215 (serde_json::Value::Object(obj), PathComponentRange::Field(range)) => {
1216 let field = &path[range.clone()];
1217 if index == parts.len() - 1 {
1218 obj.remove(field);
1219 } else if let Some(child) = obj.get_mut(field) {
1220 Self::delete_value_recursive_parsed(child, path, parts, index + 1);
1221 }
1222 }
1223 (serde_json::Value::Array(arr), PathComponentRange::ArrayIndex(idx)) => {
1224 if index == parts.len() - 1 {
1225 if *idx < arr.len() {
1226 arr.remove(*idx);
1227 }
1228 } else if *idx < arr.len() {
1229 Self::delete_value_recursive_parsed(&mut arr[*idx], path, parts, index + 1);
1230 }
1231 }
1232 _ => {}
1233 }
1234 }
1235}
1236
1237impl Default for BlackBoxProcessor {
1238 fn default() -> Self {
1239 Self::new_unfiltered()
1240 }
1241}
1242
1243#[cfg(test)]
1244mod tests {
1245 use super::*;
1246 use crate::{FilterPredicate, ReduceFunction, StreamGenerator, TransformFunction};
1247
1248 #[test]
1249 fn test_field_operations() {
1250 let mut processor = BlackBoxProcessor::new_unfiltered();
1251
1252 let operations = vec![
1253 DsonOperation::FieldAdd {
1254 path: "user.name".to_string(),
1255 value: OperationValue::StringRef("Alice".to_string()),
1256 },
1257 DsonOperation::FieldAdd {
1258 path: "user.age".to_string(),
1259 value: OperationValue::NumberRef("30".to_string()),
1260 },
1261 DsonOperation::FieldModify {
1262 path: "user.age".to_string(),
1263 value: OperationValue::NumberRef("31".to_string()),
1264 },
1265 DsonOperation::FieldDelete {
1266 path: "user.temp".to_string(),
1267 },
1268 ];
1269
1270 let result = processor
1271 .process_with_operations(r#"{"base": "data"}"#, &operations)
1272 .unwrap();
1273
1274 assert!(processor.modifications.contains_key("user.name"));
1276 assert!(processor.modifications.contains_key("user.age"));
1277 assert!(processor.deletions.contains("user.temp"));
1278
1279 println!("Field operations result: {result}");
1281 assert!(result.contains("\"user\""));
1282 assert!(result.contains("\"name\""));
1283 assert!(result.contains("\"Alice\""));
1284 assert!(result.contains("\"age\""));
1285 assert!(result.contains("31"));
1286 }
1287
1288 #[test]
1289 fn test_array_operations() {
1290 let mut processor = BlackBoxProcessor::new_unfiltered();
1291
1292 let operations = vec![
1293 DsonOperation::ArrayInsert {
1294 path: "items".to_string(),
1295 index: 0,
1296 value: OperationValue::StringRef("first".to_string()),
1297 },
1298 DsonOperation::ArrayReplace {
1299 path: "items".to_string(),
1300 index: 1,
1301 value: OperationValue::StringRef("second".to_string()),
1302 },
1303 DsonOperation::ArrayRemove {
1304 path: "items".to_string(),
1305 index: 2,
1306 },
1307 DsonOperation::ArrayFilter {
1308 path: "numbers".to_string(),
1309 predicate: FilterPredicate::Even,
1310 },
1311 DsonOperation::ArrayMap {
1312 path: "values".to_string(),
1313 transform: TransformFunction::Add(10),
1314 },
1315 ];
1316
1317 let result = processor
1318 .process_with_operations(r#"{"base": "data"}"#, &operations)
1319 .unwrap();
1320
1321 assert!(processor.modifications.contains_key("items[0]"));
1323 assert!(processor.modifications.contains_key("items[1]"));
1324 assert!(processor.deletions.contains("items[2]"));
1325 assert!(processor.modifications.contains_key("numbers.filter"));
1326 assert!(processor.modifications.contains_key("values.map"));
1327
1328 println!("Array operations result: {result}");
1329 }
1330
1331 #[test]
1332 fn test_batch_operations() {
1333 let mut processor = BlackBoxProcessor::new_unfiltered();
1334
1335 let batch_ops = vec![
1336 DsonOperation::FieldAdd {
1337 path: "batch.field1".to_string(),
1338 value: OperationValue::StringRef("value1".to_string()),
1339 },
1340 DsonOperation::FieldAdd {
1341 path: "batch.field2".to_string(),
1342 value: OperationValue::StringRef("value2".to_string()),
1343 },
1344 ];
1345
1346 let operations = vec![DsonOperation::BatchExecute {
1347 operations: batch_ops,
1348 }];
1349
1350 let result = processor
1351 .process_with_operations(r#"{"base": "data"}"#, &operations)
1352 .unwrap();
1353
1354 assert!(processor.modifications.contains_key("batch.field1"));
1356 assert!(processor.modifications.contains_key("batch.field2"));
1357
1358 println!("Batch operations result: {result}");
1359 }
1360
1361 #[test]
1362 fn test_complex_pipeline() {
1363 let mut processor = BlackBoxProcessor::new_unfiltered();
1364
1365 let operations = vec![
1366 DsonOperation::ArrayBuild {
1368 path: "data".to_string(),
1369 elements: vec![
1370 OperationValue::NumberRef("1".to_string()),
1371 OperationValue::NumberRef("2".to_string()),
1372 OperationValue::NumberRef("3".to_string()),
1373 OperationValue::NumberRef("4".to_string()),
1374 OperationValue::NumberRef("5".to_string()),
1375 ],
1376 },
1377 DsonOperation::ArrayFilter {
1379 path: "data".to_string(),
1380 predicate: FilterPredicate::Even,
1381 },
1382 DsonOperation::ArrayMap {
1384 path: "data".to_string(),
1385 transform: TransformFunction::Multiply(2),
1386 },
1387 DsonOperation::ArrayReduce {
1389 path: "data".to_string(),
1390 initial: OperationValue::NumberRef("0".to_string()),
1391 reducer: ReduceFunction::Sum,
1392 },
1393 ];
1394
1395 let result = processor
1396 .process_with_operations(r#"{"base": "data"}"#, &operations)
1397 .unwrap();
1398
1399 assert!(processor.modifications.contains_key("data"));
1401 assert!(processor.modifications.contains_key("data.filter"));
1402 assert!(processor.modifications.contains_key("data.map"));
1403 assert!(processor.modifications.contains_key("data.reduce"));
1404
1405 println!("Complex pipeline result: {result}");
1406 }
1407
1408 #[test]
1409 fn test_schema_filter_new() {
1410 let filter = SchemaFilter::new(vec!["name".to_string()]);
1411 assert!(filter.is_ok());
1412 }
1413
1414 #[test]
1415 fn test_schema_filter_matches() {
1416 let filter = SchemaFilter::new(vec!["name".to_string()]).unwrap();
1417 assert!(filter.matches("name"));
1418 assert!(!filter.matches("age"));
1419 }
1420
1421 #[test]
1422 fn test_schema_filter_wildcard() {
1423 let filter = SchemaFilter::new(vec!["users.*.id".to_string()]).unwrap();
1424 assert!(filter.matches("users.name.id"));
1425 }
1426
1427 #[test]
1428 fn test_schema_filter_paths() {
1429 let filter = SchemaFilter::new(vec!["name".to_string(), "age".to_string()]).unwrap();
1430 assert_eq!(filter.paths().len(), 2);
1431 }
1432
1433 #[test]
1434 fn test_black_box_processor_new() {
1435 let processor = BlackBoxProcessor::new(vec!["name".to_string()], vec!["name".to_string()]);
1436 assert!(processor.modifications.is_empty());
1437 }
1438
1439 #[test]
1440 fn test_black_box_processor_new_unfiltered() {
1441 let processor = BlackBoxProcessor::new_unfiltered();
1442 assert!(processor.modifications.is_empty());
1443 }
1444
1445 #[test]
1446 fn test_black_box_processor_default() {
1447 let processor = BlackBoxProcessor::default();
1448 assert!(processor.modifications.is_empty());
1449 }
1450
1451 #[test]
1452 fn test_black_box_processor_process() {
1453 let mut processor = BlackBoxProcessor::new_unfiltered();
1454 let result = processor.process(r#"{"name":"test"}"#);
1455 assert!(result.is_ok());
1456 }
1457
1458 #[test]
1459 fn test_black_box_processor_apply_operation() {
1460 let mut processor = BlackBoxProcessor::new_unfiltered();
1461 processor.process(r"{}").unwrap();
1462 let result = processor.apply_operation(&DsonOperation::FieldAdd {
1463 path: "test".to_string(),
1464 value: OperationValue::Null,
1465 });
1466 assert!(result.is_ok());
1467 }
1468
1469 #[test]
1470 fn test_black_box_processor_apply_operations() {
1471 let mut processor = BlackBoxProcessor::new_unfiltered();
1472 processor.process(r"{}").unwrap();
1473 let ops = vec![
1474 DsonOperation::FieldAdd {
1475 path: "a".to_string(),
1476 value: OperationValue::Null,
1477 },
1478 DsonOperation::FieldAdd {
1479 path: "b".to_string(),
1480 value: OperationValue::Null,
1481 },
1482 ];
1483 let result = processor.apply_operations(&ops);
1484 assert!(result.is_ok());
1485 }
1486
1487 #[test]
1488 fn test_black_box_processor_generate_output() {
1489 let mut processor = BlackBoxProcessor::new_unfiltered();
1490 processor.process(r#"{"name":"test"}"#).unwrap();
1491 let result = processor.generate_output();
1492 assert!(result.is_ok());
1493 }
1494
1495 #[test]
1496 fn test_black_box_processor_streaming_operations() {
1497 let mut processor = BlackBoxProcessor::new_unfiltered();
1498 let operations = vec![
1499 DsonOperation::StreamBuild {
1500 path: "stream".to_string(),
1501 generator: StreamGenerator::Range {
1502 start: 0,
1503 end: 5,
1504 step: 1,
1505 },
1506 },
1507 DsonOperation::StreamFilter {
1508 path: "stream".to_string(),
1509 predicate: FilterPredicate::Even,
1510 },
1511 DsonOperation::StreamMap {
1512 path: "stream".to_string(),
1513 transform: TransformFunction::Add(10),
1514 },
1515 DsonOperation::StreamEmit {
1516 path: "stream".to_string(),
1517 batch_size: 10,
1518 },
1519 ];
1520 let result = processor.process_with_operations(r"{}", &operations);
1521 assert!(result.is_ok());
1522 }
1523
1524 #[test]
1525 fn test_black_box_processor_reduce_sum() {
1526 let mut processor = BlackBoxProcessor::new_unfiltered();
1527 let operations = vec![
1528 DsonOperation::ArrayBuild {
1529 path: "nums".to_string(),
1530 elements: vec![
1531 OperationValue::NumberRef("1".to_string()),
1532 OperationValue::NumberRef("2".to_string()),
1533 OperationValue::NumberRef("3".to_string()),
1534 ],
1535 },
1536 DsonOperation::ArrayReduce {
1537 path: "nums".to_string(),
1538 initial: OperationValue::NumberRef("0".to_string()),
1539 reducer: ReduceFunction::Sum,
1540 },
1541 ];
1542 let result = processor.process_with_operations(r"{}", &operations);
1543 assert!(result.is_ok());
1544 }
1545
1546 #[test]
1547 fn test_black_box_processor_reduce_product() {
1548 let mut processor = BlackBoxProcessor::new_unfiltered();
1549 let operations = vec![
1550 DsonOperation::ArrayBuild {
1551 path: "nums".to_string(),
1552 elements: vec![
1553 OperationValue::NumberRef("2".to_string()),
1554 OperationValue::NumberRef("3".to_string()),
1555 ],
1556 },
1557 DsonOperation::ArrayReduce {
1558 path: "nums".to_string(),
1559 initial: OperationValue::NumberRef("1".to_string()),
1560 reducer: ReduceFunction::Product,
1561 },
1562 ];
1563 let result = processor.process_with_operations(r"{}", &operations);
1564 assert!(result.is_ok());
1565 }
1566
1567 #[test]
1568 fn test_black_box_processor_reduce_min() {
1569 let mut processor = BlackBoxProcessor::new_unfiltered();
1570 let operations = vec![DsonOperation::ArrayReduce {
1571 path: "nums".to_string(),
1572 initial: OperationValue::NumberRef("999".to_string()),
1573 reducer: ReduceFunction::Min,
1574 }];
1575 let result = processor.process_with_operations(r"{}", &operations);
1576 assert!(result.is_ok());
1577 }
1578
1579 #[test]
1580 fn test_black_box_processor_reduce_max() {
1581 let mut processor = BlackBoxProcessor::new_unfiltered();
1582 let operations = vec![DsonOperation::ArrayReduce {
1583 path: "nums".to_string(),
1584 initial: OperationValue::NumberRef("0".to_string()),
1585 reducer: ReduceFunction::Max,
1586 }];
1587 let result = processor.process_with_operations(r"{}", &operations);
1588 assert!(result.is_ok());
1589 }
1590
1591 #[test]
1592 fn test_black_box_processor_reduce_count() {
1593 let mut processor = BlackBoxProcessor::new_unfiltered();
1594 let operations = vec![DsonOperation::ArrayReduce {
1595 path: "nums".to_string(),
1596 initial: OperationValue::NumberRef("0".to_string()),
1597 reducer: ReduceFunction::Count,
1598 }];
1599 let result = processor.process_with_operations(r"{}", &operations);
1600 assert!(result.is_ok());
1601 }
1602
1603 #[test]
1604 fn test_black_box_processor_reduce_concat() {
1605 let mut processor = BlackBoxProcessor::new_unfiltered();
1606 let operations = vec![DsonOperation::ArrayReduce {
1607 path: "strs".to_string(),
1608 initial: OperationValue::StringRef(String::new()),
1609 reducer: ReduceFunction::Concat,
1610 }];
1611 let result = processor.process_with_operations(r"{}", &operations);
1612 assert!(result.is_ok());
1613 }
1614
1615 #[test]
1616 fn test_black_box_processor_filter_odd() {
1617 let mut processor = BlackBoxProcessor::new_unfiltered();
1618 let operations = vec![DsonOperation::ArrayFilter {
1619 path: "nums".to_string(),
1620 predicate: FilterPredicate::Odd,
1621 }];
1622 let result = processor.process_with_operations(r"{}", &operations);
1623 assert!(result.is_ok());
1624 }
1625
1626 #[test]
1627 fn test_black_box_processor_filter_greater_than() {
1628 let mut processor = BlackBoxProcessor::new_unfiltered();
1629 let operations = vec![DsonOperation::ArrayFilter {
1630 path: "nums".to_string(),
1631 predicate: FilterPredicate::GreaterThan(5),
1632 }];
1633 let result = processor.process_with_operations(r"{}", &operations);
1634 assert!(result.is_ok());
1635 }
1636
1637 #[test]
1638 fn test_black_box_processor_filter_less_than() {
1639 let mut processor = BlackBoxProcessor::new_unfiltered();
1640 let operations = vec![DsonOperation::ArrayFilter {
1641 path: "nums".to_string(),
1642 predicate: FilterPredicate::LessThan(5),
1643 }];
1644 let result = processor.process_with_operations(r"{}", &operations);
1645 assert!(result.is_ok());
1646 }
1647
1648 #[test]
1649 fn test_black_box_processor_filter_every_nth() {
1650 let mut processor = BlackBoxProcessor::new_unfiltered();
1651 let operations = vec![DsonOperation::ArrayFilter {
1652 path: "nums".to_string(),
1653 predicate: FilterPredicate::EveryNth(3),
1654 }];
1655 let result = processor.process_with_operations(r"{}", &operations);
1656 assert!(result.is_ok());
1657 }
1658
1659 #[test]
1660 fn test_black_box_processor_filter_alternate() {
1661 let mut processor = BlackBoxProcessor::new_unfiltered();
1662 let operations = vec![DsonOperation::ArrayFilter {
1663 path: "nums".to_string(),
1664 predicate: FilterPredicate::Alternate,
1665 }];
1666 let result = processor.process_with_operations(r"{}", &operations);
1667 assert!(result.is_ok());
1668 }
1669
1670 #[test]
1671 fn test_black_box_processor_transform_multiply() {
1672 let mut processor = BlackBoxProcessor::new_unfiltered();
1673 let operations = vec![DsonOperation::ArrayMap {
1674 path: "nums".to_string(),
1675 transform: TransformFunction::Multiply(2),
1676 }];
1677 let result = processor.process_with_operations(r"{}", &operations);
1678 assert!(result.is_ok());
1679 }
1680
1681 #[test]
1682 fn test_black_box_processor_transform_uppercase() {
1683 let mut processor = BlackBoxProcessor::new_unfiltered();
1684 let operations = vec![DsonOperation::ArrayMap {
1685 path: "strs".to_string(),
1686 transform: TransformFunction::ToUppercase,
1687 }];
1688 let result = processor.process_with_operations(r"{}", &operations);
1689 assert!(result.is_ok());
1690 }
1691
1692 #[test]
1693 fn test_black_box_processor_transform_lowercase() {
1694 let mut processor = BlackBoxProcessor::new_unfiltered();
1695 let operations = vec![DsonOperation::ArrayMap {
1696 path: "strs".to_string(),
1697 transform: TransformFunction::ToLowercase,
1698 }];
1699 let result = processor.process_with_operations(r"{}", &operations);
1700 assert!(result.is_ok());
1701 }
1702
1703 #[test]
1704 fn test_black_box_processor_transform_append() {
1705 let mut processor = BlackBoxProcessor::new_unfiltered();
1706 let operations = vec![DsonOperation::ArrayMap {
1707 path: "strs".to_string(),
1708 transform: TransformFunction::Append("!".to_string()),
1709 }];
1710 let result = processor.process_with_operations(r"{}", &operations);
1711 assert!(result.is_ok());
1712 }
1713
1714 #[test]
1715 fn test_black_box_processor_transform_prepend() {
1716 let mut processor = BlackBoxProcessor::new_unfiltered();
1717 let operations = vec![DsonOperation::ArrayMap {
1718 path: "strs".to_string(),
1719 transform: TransformFunction::Prepend(">>>".to_string()),
1720 }];
1721 let result = processor.process_with_operations(r"{}", &operations);
1722 assert!(result.is_ok());
1723 }
1724
1725 #[test]
1726 fn test_black_box_processor_stream_fibonacci() {
1727 let mut processor = BlackBoxProcessor::new_unfiltered();
1728 let operations = vec![DsonOperation::StreamBuild {
1729 path: "fib".to_string(),
1730 generator: StreamGenerator::Fibonacci(5),
1731 }];
1732 let result = processor.process_with_operations(r"{}", &operations);
1733 assert!(result.is_ok());
1734 }
1735
1736 #[test]
1737 fn test_black_box_processor_stream_repeat() {
1738 let mut processor = BlackBoxProcessor::new_unfiltered();
1739 let operations = vec![DsonOperation::StreamBuild {
1740 path: "repeated".to_string(),
1741 generator: StreamGenerator::Repeat(OperationValue::NumberRef("42".to_string()), 3),
1742 }];
1743 let result = processor.process_with_operations(r"{}", &operations);
1744 assert!(result.is_ok());
1745 }
1746
1747 #[test]
1748 fn test_schema_filter_clone() {
1749 let filter = SchemaFilter::new(vec!["name".to_string()]).unwrap();
1750 let cloned = filter;
1751 assert_eq!(cloned.paths().len(), 1);
1752 }
1753
1754 #[test]
1755 fn test_schema_filter_debug() {
1756 let filter = SchemaFilter::new(vec!["name".to_string()]).unwrap();
1757 let debug = format!("{filter:?}");
1758 assert!(debug.contains("SchemaFilter"));
1759 }
1760
1761 #[test]
1763 fn test_json_path_context_new() {
1764 let paths = FastHashSet::default();
1765 let context = JsonPathContext::new(paths);
1766 assert_eq!(context.depth, 0);
1767 }
1768
1769 #[test]
1770 fn test_json_path_context_enter_exit_scope() {
1771 let paths = FastHashSet::default();
1772 let mut context = JsonPathContext::new(paths);
1773 context.enter_scope("user");
1774 assert_eq!(context.depth, 1);
1775 assert_eq!(context.current_path(), "user");
1776 context.enter_scope("name");
1777 assert_eq!(context.depth, 2);
1778 assert_eq!(context.current_path(), "user.name");
1779 context.exit_scope();
1780 assert_eq!(context.depth, 1);
1781 context.exit_scope();
1782 assert_eq!(context.depth, 0);
1783 }
1784
1785 #[test]
1786 fn test_json_path_context_exit_scope_empty() {
1787 let paths = FastHashSet::default();
1788 let mut context = JsonPathContext::new(paths);
1789 context.exit_scope();
1791 assert_eq!(context.depth, 0);
1792 }
1793
1794 #[test]
1795 fn test_json_path_context_should_process() {
1796 let mut paths = FastHashSet::default();
1797 paths.insert("user.name".to_string());
1798 let mut context = JsonPathContext::new(paths);
1799 context.enter_scope("user");
1800 assert!(context.should_process());
1801 }
1802
1803 #[test]
1804 fn test_json_path_context_is_path_relevant() {
1805 let mut paths = FastHashSet::default();
1806 paths.insert("user".to_string());
1807 let context = JsonPathContext::new(paths);
1808 assert!(context.is_path_relevant("user.name"));
1809 assert!(!context.is_path_relevant("other"));
1810 }
1811
1812 #[test]
1813 fn test_json_path_context_clone() {
1814 let paths = FastHashSet::default();
1815 let context = JsonPathContext::new(paths);
1816 let cloned = context;
1817 assert_eq!(cloned.depth, 0);
1818 }
1819
1820 #[test]
1821 fn test_json_path_context_debug() {
1822 let paths = FastHashSet::default();
1823 let context = JsonPathContext::new(paths);
1824 let debug = format!("{context:?}");
1825 assert!(debug.contains("JsonPathContext"));
1826 }
1827
1828 #[test]
1830 fn test_processing_mode_fast() {
1831 let mode = ProcessingMode::Fast;
1832 assert_eq!(mode, ProcessingMode::Fast);
1833 }
1834
1835 #[test]
1836 fn test_processing_mode_balanced() {
1837 let mode = ProcessingMode::Balanced;
1838 assert_eq!(mode, ProcessingMode::Balanced);
1839 }
1840
1841 #[test]
1842 fn test_processing_mode_memory_efficient() {
1843 let mode = ProcessingMode::MemoryEfficient;
1844 assert_eq!(mode, ProcessingMode::MemoryEfficient);
1845 }
1846
1847 #[test]
1848 fn test_processing_mode_clone() {
1849 let mode = ProcessingMode::Fast;
1850 let cloned = mode;
1851 assert_eq!(cloned, ProcessingMode::Fast);
1852 }
1853
1854 #[test]
1855 fn test_processing_mode_debug() {
1856 let mode = ProcessingMode::Fast;
1857 let debug = format!("{mode:?}");
1858 assert!(debug.contains("Fast"));
1859 }
1860
1861 #[test]
1863 fn test_schema_filter_array_wildcard() {
1864 let filter = SchemaFilter::new(vec!["users[*].name".to_string()]).unwrap();
1865 assert_eq!(filter.paths().len(), 1);
1867 }
1870
1871 #[test]
1872 fn test_schema_filter_double_wildcard() {
1873 let filter = SchemaFilter::new(vec!["data.**".to_string()]).unwrap();
1874 let result = filter.matches("data.user.name");
1876 let _ = result;
1878 }
1879
1880 #[test]
1881 fn test_schema_filter_get_matching_paths() {
1882 let filter =
1883 SchemaFilter::new(vec!["user.name".to_string(), "user.age".to_string()]).unwrap();
1884 let matches = filter.get_matching_paths("user.name");
1887 assert!(!matches.is_empty());
1888 }
1889
1890 #[test]
1891 fn test_schema_filter_exact_match() {
1892 let filter = SchemaFilter::new(vec!["user.name".to_string()]).unwrap();
1893 assert!(filter.matches("user.name"));
1894 assert!(!filter.matches("user.age"));
1895 }
1896
1897 #[test]
1898 fn test_schema_filter_prefix_match() {
1899 let filter = SchemaFilter::new(vec!["user".to_string()]).unwrap();
1900 assert!(filter.matches("user"));
1902 }
1903
1904 #[test]
1906 fn test_black_box_processor_with_input_schema() {
1907 let processor = BlackBoxProcessor::new(vec!["user.name".to_string()], vec![]);
1908 assert!(processor.input_filter.is_some());
1909 }
1910
1911 #[test]
1912 fn test_black_box_processor_with_output_schema() {
1913 let processor = BlackBoxProcessor::new(vec![], vec!["user.name".to_string()]);
1914 assert!(processor.output_filter.is_some());
1915 }
1916
1917 #[test]
1918 fn test_black_box_processor_with_both_schemas() {
1919 let processor =
1920 BlackBoxProcessor::new(vec!["user.name".to_string()], vec!["user.name".to_string()]);
1921 assert!(processor.input_filter.is_some());
1922 assert!(processor.output_filter.is_some());
1923 }
1924
1925 #[test]
1926 fn test_black_box_processor_process_with_input_filter() {
1927 let mut processor = BlackBoxProcessor::new(vec!["name".to_string()], vec![]);
1928 let result = processor.process(r#"{"name": "Alice", "age": 30}"#);
1929 assert!(result.is_ok());
1930 }
1931
1932 #[test]
1933 fn test_black_box_processor_apply_operations_canonical() {
1934 let mut processor = BlackBoxProcessor::new_unfiltered();
1935 processor.process(r"{}").unwrap();
1936 let ops = vec![DsonOperation::FieldAdd {
1937 path: "test".to_string(),
1938 value: OperationValue::Null,
1939 }];
1940 let result = processor.apply_operations_canonical(&ops);
1941 assert!(result.is_ok());
1942 }
1943
1944 #[test]
1945 fn test_black_box_processor_process_with_operations_canonical() {
1946 let mut processor = BlackBoxProcessor::new_unfiltered();
1947 let ops = vec![DsonOperation::FieldAdd {
1948 path: "test".to_string(),
1949 value: OperationValue::Null,
1950 }];
1951 let result = processor.process_with_operations_canonical(r"{}", &ops);
1952 assert!(result.is_ok());
1953 }
1954
1955 #[test]
1956 fn test_black_box_processor_object_operations() {
1957 let mut processor = BlackBoxProcessor::new_unfiltered();
1958 let operations = vec![
1959 DsonOperation::ObjectStart {
1960 path: "obj".to_string(),
1961 },
1962 DsonOperation::FieldAdd {
1963 path: "obj.field".to_string(),
1964 value: OperationValue::StringRef("value".to_string()),
1965 },
1966 DsonOperation::ObjectEnd {
1967 path: "obj".to_string(),
1968 },
1969 ];
1970 let result = processor.process_with_operations(r"{}", &operations);
1971 assert!(result.is_ok());
1972 }
1973
1974 #[test]
1975 fn test_black_box_processor_array_start_end() {
1976 let mut processor = BlackBoxProcessor::new_unfiltered();
1977 let operations = vec![
1978 DsonOperation::ArrayStart {
1979 path: "arr".to_string(),
1980 },
1981 DsonOperation::ArrayEnd {
1982 path: "arr".to_string(),
1983 },
1984 ];
1985 let result = processor.process_with_operations(r"{}", &operations);
1986 assert!(result.is_ok());
1987 }
1988
1989 #[test]
1990 fn test_black_box_processor_merge_field() {
1991 let mut processor = BlackBoxProcessor::new_unfiltered();
1992 let operations = vec![DsonOperation::MergeField {
1993 path: "counter".to_string(),
1994 value: OperationValue::NumberRef("10".to_string()),
1995 timestamp: 100,
1996 }];
1997 let result = processor.process_with_operations(r"{}", &operations);
1998 assert!(result.is_ok());
1999 }
2000
2001 #[test]
2002 fn test_black_box_processor_check_presence() {
2003 let mut processor = BlackBoxProcessor::new_unfiltered();
2004 let operations = vec![DsonOperation::CheckPresence {
2005 path: "field".to_string(),
2006 }];
2007 let result = processor.process_with_operations(r"{}", &operations);
2008 assert!(result.is_ok());
2009 }
2010
2011 #[test]
2012 fn test_black_box_processor_check_absence() {
2013 let mut processor = BlackBoxProcessor::new_unfiltered();
2014 let operations = vec![DsonOperation::CheckAbsence {
2015 path: "field".to_string(),
2016 }];
2017 let result = processor.process_with_operations(r"{}", &operations);
2018 assert!(result.is_ok());
2019 }
2020
2021 #[test]
2022 fn test_black_box_processor_conflict_resolve() {
2023 let mut processor = BlackBoxProcessor::new_unfiltered();
2024 let operations = vec![DsonOperation::ConflictResolve {
2025 path: "field".to_string(),
2026 strategy: crate::MergeStrategy::LastWriteWins,
2027 }];
2028 let result = processor.process_with_operations(r"{}", &operations);
2029 assert!(result.is_ok());
2030 }
2031
2032 #[test]
2033 fn test_black_box_processor_stream_emit() {
2034 let mut processor = BlackBoxProcessor::new_unfiltered();
2035 let operations = vec![
2036 DsonOperation::StreamBuild {
2037 path: "s".to_string(),
2038 generator: StreamGenerator::Range {
2039 start: 0,
2040 end: 3,
2041 step: 1,
2042 },
2043 },
2044 DsonOperation::StreamEmit {
2045 path: "s".to_string(),
2046 batch_size: 3,
2047 },
2048 ];
2049 let result = processor.process_with_operations(r"{}", &operations);
2050 assert!(result.is_ok());
2051 }
2052
2053 #[test]
2054 fn test_black_box_processor_complex_json() {
2055 let mut processor = BlackBoxProcessor::new_unfiltered();
2056 let json = r#"{"user": {"name": "Alice", "scores": [1, 2, 3]}}"#;
2057 let result = processor.process(json);
2058 assert!(result.is_ok());
2059 }
2060
2061 #[test]
2062 fn test_black_box_processor_nested_operations() {
2063 let mut processor = BlackBoxProcessor::new_unfiltered();
2064 let operations = vec![DsonOperation::FieldAdd {
2065 path: "a.b.c".to_string(),
2066 value: OperationValue::StringRef("deep".to_string()),
2067 }];
2068 let result = processor.process_with_operations(r"{}", &operations);
2069 assert!(result.is_ok());
2070 }
2071
2072 #[test]
2073 fn test_black_box_processor_array_remove() {
2074 let mut processor = BlackBoxProcessor::new_unfiltered();
2075 let operations = vec![DsonOperation::ArrayRemove {
2076 path: "items".to_string(),
2077 index: 0,
2078 }];
2079 let result = processor.process_with_operations(r"{}", &operations);
2080 assert!(result.is_ok());
2081 }
2082
2083 #[test]
2084 fn test_black_box_processor_array_insert_multiple() {
2085 let mut processor = BlackBoxProcessor::new_unfiltered();
2086 let operations = vec![
2087 DsonOperation::ArrayInsert {
2088 path: "items".to_string(),
2089 index: 0,
2090 value: OperationValue::NumberRef("1".to_string()),
2091 },
2092 DsonOperation::ArrayInsert {
2093 path: "items".to_string(),
2094 index: 1,
2095 value: OperationValue::NumberRef("2".to_string()),
2096 },
2097 ];
2098 let result = processor.process_with_operations(r"{}", &operations);
2099 assert!(result.is_ok());
2100 }
2101
2102 #[test]
2103 fn test_black_box_processor_array_replace_multiple() {
2104 let mut processor = BlackBoxProcessor::new_unfiltered();
2105 let operations = vec![DsonOperation::ArrayReplace {
2106 path: "items".to_string(),
2107 index: 0,
2108 value: OperationValue::StringRef("replaced".to_string()),
2109 }];
2110 let result = processor.process_with_operations(r"{}", &operations);
2111 assert!(result.is_ok());
2112 }
2113
2114 #[test]
2115 fn test_black_box_processor_stream_with_array_reduce() {
2116 let mut processor = BlackBoxProcessor::new_unfiltered();
2117 let operations = vec![
2118 DsonOperation::StreamBuild {
2119 path: "s".to_string(),
2120 generator: StreamGenerator::Range {
2121 start: 1,
2122 end: 5,
2123 step: 1,
2124 },
2125 },
2126 DsonOperation::ArrayReduce {
2127 path: "s".to_string(),
2128 initial: OperationValue::NumberRef("0".to_string()),
2129 reducer: ReduceFunction::Sum,
2130 },
2131 ];
2132 let result = processor.process_with_operations(r"{}", &operations);
2133 assert!(result.is_ok());
2134 }
2135
2136 #[test]
2139 fn test_black_box_processor_read_field_no_tape() {
2140 let processor = BlackBoxProcessor::new_unfiltered();
2141 let result = processor.read_field("some.path");
2142 assert!(result.is_ok());
2143 assert!(result.unwrap().is_none());
2144 }
2145
2146 #[test]
2147 fn test_black_box_processor_read_field_with_tape() {
2148 let mut processor = BlackBoxProcessor::new_unfiltered();
2149 processor.process(r#"{"name": "Alice"}"#).unwrap();
2150 let result = processor.read_field("name");
2151 assert!(result.is_ok());
2152 }
2153
2154 #[test]
2155 fn test_black_box_processor_read_field_value_no_tape() {
2156 let processor = BlackBoxProcessor::new_unfiltered();
2157 let result = processor.read_field_value("some.path");
2158 assert!(result.is_ok());
2159 assert!(result.unwrap().is_none());
2160 }
2161
2162 #[test]
2163 fn test_black_box_processor_read_field_value_from_modifications() {
2164 let mut processor = BlackBoxProcessor::new_unfiltered();
2165 processor.process(r"{}").unwrap();
2166 processor
2168 .apply_operation(&DsonOperation::FieldAdd {
2169 path: "test".to_string(),
2170 value: OperationValue::StringRef("value".to_string()),
2171 })
2172 .unwrap();
2173 let result = processor.read_field_value("test");
2175 assert!(result.is_ok());
2176 assert!(result.unwrap().is_some());
2177 }
2178
2179 #[test]
2180 fn test_black_box_processor_write_field() {
2181 let mut processor = BlackBoxProcessor::new_unfiltered();
2182 processor.process(r"{}").unwrap();
2183 let node = simd_json::value::tape::Node::String("test");
2184 let result = processor.write_field("new.field", node);
2185 assert!(result.is_ok());
2186 assert!(processor.modifications.contains_key("new.field"));
2187 }
2188
2189 #[test]
2190 fn test_black_box_processor_write_field_bool() {
2191 let mut processor = BlackBoxProcessor::new_unfiltered();
2192 processor.process(r"{}").unwrap();
2193 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::Bool(true));
2194 let result = processor.write_field("bool.field", node);
2195 assert!(result.is_ok());
2196 }
2197
2198 #[test]
2199 fn test_black_box_processor_write_field_null() {
2200 let mut processor = BlackBoxProcessor::new_unfiltered();
2201 processor.process(r"{}").unwrap();
2202 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::Null);
2203 let result = processor.write_field("null.field", node);
2204 assert!(result.is_ok());
2205 }
2206
2207 #[test]
2208 fn test_black_box_processor_write_field_i64() {
2209 let mut processor = BlackBoxProcessor::new_unfiltered();
2210 processor.process(r"{}").unwrap();
2211 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::I64(-42));
2212 let result = processor.write_field("int.field", node);
2213 assert!(result.is_ok());
2214 }
2215
2216 #[test]
2217 fn test_black_box_processor_write_field_u64() {
2218 let mut processor = BlackBoxProcessor::new_unfiltered();
2219 processor.process(r"{}").unwrap();
2220 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::U64(42));
2221 let result = processor.write_field("uint.field", node);
2222 assert!(result.is_ok());
2223 }
2224
2225 #[test]
2226 fn test_black_box_processor_write_field_f64() {
2227 let mut processor = BlackBoxProcessor::new_unfiltered();
2228 processor.process(r"{}").unwrap();
2229 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::F64(2.5));
2230 let result = processor.write_field("float.field", node);
2231 assert!(result.is_ok());
2232 }
2233
2234 #[test]
2235 fn test_black_box_processor_write_field_object() {
2236 let mut processor = BlackBoxProcessor::new_unfiltered();
2237 processor.process(r"{}").unwrap();
2238 let node = simd_json::value::tape::Node::Object { len: 0, count: 0 };
2239 let result = processor.write_field("obj.field", node);
2240 assert!(result.is_ok());
2241 }
2242
2243 #[test]
2244 fn test_black_box_processor_write_field_array() {
2245 let mut processor = BlackBoxProcessor::new_unfiltered();
2246 processor.process(r"{}").unwrap();
2247 let node = simd_json::value::tape::Node::Array { len: 0, count: 0 };
2248 let result = processor.write_field("arr.field", node);
2249 assert!(result.is_ok());
2250 }
2251
2252 #[test]
2253 fn test_black_box_processor_advance_field_no_tape() {
2254 let processor = BlackBoxProcessor::new_unfiltered();
2255 let result = processor.advance_field();
2256 assert!(result.is_ok());
2257 assert!(!result.unwrap());
2258 }
2259
2260 #[test]
2261 fn test_black_box_processor_advance_field_with_tape() {
2262 let mut processor = BlackBoxProcessor::new_unfiltered();
2263 processor.process(r#"{"a": 1, "b": 2}"#).unwrap();
2264 let result = processor.advance_field();
2265 assert!(result.is_ok());
2266 }
2267
2268 #[test]
2269 fn test_black_box_processor_push_record() {
2270 let mut processor = BlackBoxProcessor::new_unfiltered();
2271 processor.process(r"{}").unwrap();
2272 let node = simd_json::value::tape::Node::String("record");
2273 let result = processor.push_record(node);
2274 assert!(result.is_ok());
2275 assert!(!processor.stream_buffer.is_empty());
2276 }
2277
2278 #[test]
2279 fn test_black_box_processor_push_record_bool() {
2280 let mut processor = BlackBoxProcessor::new_unfiltered();
2281 processor.process(r"{}").unwrap();
2282 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::Bool(true));
2283 let result = processor.push_record(node);
2284 assert!(result.is_ok());
2285 }
2286
2287 #[test]
2288 fn test_black_box_processor_push_record_null() {
2289 let mut processor = BlackBoxProcessor::new_unfiltered();
2290 processor.process(r"{}").unwrap();
2291 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::Null);
2292 let result = processor.push_record(node);
2293 assert!(result.is_ok());
2294 }
2295
2296 #[test]
2297 fn test_black_box_processor_push_record_i64() {
2298 let mut processor = BlackBoxProcessor::new_unfiltered();
2299 processor.process(r"{}").unwrap();
2300 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::I64(-10));
2301 let result = processor.push_record(node);
2302 assert!(result.is_ok());
2303 }
2304
2305 #[test]
2306 fn test_black_box_processor_push_record_u64() {
2307 let mut processor = BlackBoxProcessor::new_unfiltered();
2308 processor.process(r"{}").unwrap();
2309 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::U64(10));
2310 let result = processor.push_record(node);
2311 assert!(result.is_ok());
2312 }
2313
2314 #[test]
2315 fn test_black_box_processor_push_record_f64() {
2316 let mut processor = BlackBoxProcessor::new_unfiltered();
2317 processor.process(r"{}").unwrap();
2318 let node = simd_json::value::tape::Node::Static(simd_json::StaticNode::F64(1.5));
2319 let result = processor.push_record(node);
2320 assert!(result.is_ok());
2321 }
2322
2323 #[test]
2324 fn test_black_box_processor_push_record_object() {
2325 let mut processor = BlackBoxProcessor::new_unfiltered();
2326 processor.process(r"{}").unwrap();
2327 let node = simd_json::value::tape::Node::Object { len: 0, count: 0 };
2328 let result = processor.push_record(node);
2329 assert!(result.is_ok());
2330 }
2331
2332 #[test]
2333 fn test_black_box_processor_advance_array_index_no_tape() {
2334 let processor = BlackBoxProcessor::new_unfiltered();
2335 let result = processor.advance_array_index();
2336 assert!(result.is_ok());
2337 assert!(!result.unwrap());
2338 }
2339
2340 #[test]
2341 fn test_black_box_processor_advance_array_index_with_tape() {
2342 let mut processor = BlackBoxProcessor::new_unfiltered();
2343 processor.process(r"[1, 2, 3]").unwrap();
2344 let result = processor.advance_array_index();
2345 assert!(result.is_ok());
2346 }
2347
2348 #[test]
2349 fn test_black_box_processor_input_schema_empty() {
2350 let processor = BlackBoxProcessor::new_unfiltered();
2351 assert!(processor.input_schema().is_empty());
2352 }
2353
2354 #[test]
2355 fn test_black_box_processor_input_schema_non_empty() {
2356 let processor = BlackBoxProcessor::new(vec!["user.name".to_string()], vec![]);
2357 let schema = processor.input_schema();
2358 assert_eq!(schema.len(), 1);
2359 assert_eq!(schema[0], "user.name");
2360 }
2361
2362 #[test]
2363 fn test_black_box_processor_output_schema_empty() {
2364 let processor = BlackBoxProcessor::new_unfiltered();
2365 assert!(processor.output_schema().is_empty());
2366 }
2367
2368 #[test]
2369 fn test_black_box_processor_output_schema_non_empty() {
2370 let processor = BlackBoxProcessor::new(vec![], vec!["user.email".to_string()]);
2371 let schema = processor.output_schema();
2372 assert_eq!(schema.len(), 1);
2373 assert_eq!(schema[0], "user.email");
2374 }
2375
2376 #[test]
2377 fn test_black_box_processor_modifications() {
2378 let mut processor = BlackBoxProcessor::new_unfiltered();
2379 processor.process(r"{}").unwrap();
2380 processor
2381 .apply_operation(&DsonOperation::FieldAdd {
2382 path: "test".to_string(),
2383 value: OperationValue::StringRef("value".to_string()),
2384 })
2385 .unwrap();
2386 let mods = processor.modifications();
2387 assert!(mods.contains_key("test"));
2388 }
2389
2390 #[test]
2391 fn test_black_box_processor_deletions() {
2392 let mut processor = BlackBoxProcessor::new_unfiltered();
2393 processor.process(r"{}").unwrap();
2394 processor
2395 .apply_operation(&DsonOperation::FieldDelete {
2396 path: "test".to_string(),
2397 })
2398 .unwrap();
2399 let dels = processor.deletions();
2400 assert!(dels.contains("test"));
2401 }
2402
2403 #[test]
2404 fn test_determine_processing_mode_fast() {
2405 let processor = BlackBoxProcessor::new_unfiltered();
2406 let mode = processor.determine_processing_mode(5000, 5);
2407 assert_eq!(mode, ProcessingMode::Fast);
2408 }
2409
2410 #[test]
2411 fn test_determine_processing_mode_balanced() {
2412 let processor = BlackBoxProcessor::new_unfiltered();
2413 let mode = processor.determine_processing_mode(500_000, 50);
2414 assert_eq!(mode, ProcessingMode::Balanced);
2415 }
2416
2417 #[test]
2418 fn test_determine_processing_mode_memory_efficient_large_doc() {
2419 let processor = BlackBoxProcessor::new_unfiltered();
2420 let mode = processor.determine_processing_mode(2_000_000, 10);
2421 assert_eq!(mode, ProcessingMode::MemoryEfficient);
2422 }
2423
2424 #[test]
2425 fn test_determine_processing_mode_memory_efficient_many_ops() {
2426 let processor = BlackBoxProcessor::new_unfiltered();
2427 let mode = processor.determine_processing_mode(50_000, 200);
2428 assert_eq!(mode, ProcessingMode::MemoryEfficient);
2429 }
2430
2431 #[test]
2432 fn test_black_box_processor_generate_output_no_tape() {
2433 let processor = BlackBoxProcessor::new_unfiltered();
2434 let result = processor.generate_output();
2435 assert!(result.is_ok());
2436 assert_eq!(result.unwrap(), "{}");
2437 }
2438
2439 #[test]
2440 fn test_black_box_processor_stream_custom_generator() {
2441 let mut processor = BlackBoxProcessor::new_unfiltered();
2442 let operations = vec![DsonOperation::StreamBuild {
2443 path: "custom".to_string(),
2444 generator: StreamGenerator::Custom("my_generator".to_string()),
2445 }];
2446 let result = processor.process_with_operations(r"{}", &operations);
2447 assert!(result.is_ok());
2448 }
2449
2450 #[test]
2451 fn test_black_box_processor_stream_filter_odd() {
2452 let mut processor = BlackBoxProcessor::new_unfiltered();
2453 let operations = vec![DsonOperation::StreamFilter {
2454 path: "s".to_string(),
2455 predicate: FilterPredicate::Odd,
2456 }];
2457 let result = processor.process_with_operations(r"{}", &operations);
2458 assert!(result.is_ok());
2459 }
2460
2461 #[test]
2462 fn test_black_box_processor_stream_filter_every_nth() {
2463 let mut processor = BlackBoxProcessor::new_unfiltered();
2464 let operations = vec![DsonOperation::StreamFilter {
2465 path: "s".to_string(),
2466 predicate: FilterPredicate::EveryNth(3),
2467 }];
2468 let result = processor.process_with_operations(r"{}", &operations);
2469 assert!(result.is_ok());
2470 }
2471
2472 #[test]
2473 fn test_black_box_processor_stream_filter_greater_than() {
2474 let mut processor = BlackBoxProcessor::new_unfiltered();
2475 let operations = vec![DsonOperation::StreamFilter {
2476 path: "s".to_string(),
2477 predicate: FilterPredicate::GreaterThan(10),
2478 }];
2479 let result = processor.process_with_operations(r"{}", &operations);
2480 assert!(result.is_ok());
2481 }
2482
2483 #[test]
2484 fn test_black_box_processor_stream_filter_less_than() {
2485 let mut processor = BlackBoxProcessor::new_unfiltered();
2486 let operations = vec![DsonOperation::StreamFilter {
2487 path: "s".to_string(),
2488 predicate: FilterPredicate::LessThan(5),
2489 }];
2490 let result = processor.process_with_operations(r"{}", &operations);
2491 assert!(result.is_ok());
2492 }
2493
2494 #[test]
2495 fn test_black_box_processor_stream_map_multiply() {
2496 let mut processor = BlackBoxProcessor::new_unfiltered();
2497 let operations = vec![DsonOperation::StreamMap {
2498 path: "s".to_string(),
2499 transform: TransformFunction::Multiply(3),
2500 }];
2501 let result = processor.process_with_operations(r"{}", &operations);
2502 assert!(result.is_ok());
2503 }
2504
2505 #[test]
2506 fn test_black_box_processor_stream_map_uppercase() {
2507 let mut processor = BlackBoxProcessor::new_unfiltered();
2508 let operations = vec![DsonOperation::StreamMap {
2509 path: "s".to_string(),
2510 transform: TransformFunction::ToUppercase,
2511 }];
2512 let result = processor.process_with_operations(r"{}", &operations);
2513 assert!(result.is_ok());
2514 }
2515
2516 #[test]
2517 fn test_black_box_processor_stream_map_lowercase() {
2518 let mut processor = BlackBoxProcessor::new_unfiltered();
2519 let operations = vec![DsonOperation::StreamMap {
2520 path: "s".to_string(),
2521 transform: TransformFunction::ToLowercase,
2522 }];
2523 let result = processor.process_with_operations(r"{}", &operations);
2524 assert!(result.is_ok());
2525 }
2526
2527 #[test]
2528 fn test_black_box_processor_check_null() {
2529 let mut processor = BlackBoxProcessor::new_unfiltered();
2530 let operations = vec![DsonOperation::CheckNull {
2531 path: "field".to_string(),
2532 }];
2533 let result = processor.process_with_operations(r"{}", &operations);
2534 assert!(result.is_ok());
2535 }
2536
2537 #[test]
2538 fn test_black_box_processor_check_not_null() {
2539 let mut processor = BlackBoxProcessor::new_unfiltered();
2540 let operations = vec![DsonOperation::CheckNotNull {
2541 path: "field".to_string(),
2542 }];
2543 let result = processor.process_with_operations(r"{}", &operations);
2544 assert!(result.is_ok());
2545 }
2546
2547 #[test]
2548 fn test_black_box_processor_with_output_filter_array() {
2549 let mut processor = BlackBoxProcessor::new(vec![], vec!["items[*]".to_string()]);
2550 let result = processor.process(r#"{"items": [1, 2, 3], "other": "value"}"#);
2551 assert!(result.is_ok());
2552 }
2553
2554 #[test]
2555 fn test_schema_filter_specific_array_index() {
2556 let filter = SchemaFilter::new(vec!["items[0]".to_string()]).unwrap();
2557 assert!(filter.matches("items[0]"));
2558 }
2559
2560 #[test]
2561 fn test_schema_filter_path_matches_pattern_wildcard() {
2562 let filter = SchemaFilter::new(vec!["users[*].id".to_string()]).unwrap();
2563 let matches = filter.get_matching_paths("users[0].id");
2565 assert!(!matches.is_empty());
2567 }
2568
2569 #[test]
2570 fn test_schema_filter_path_matches_pattern_double_wildcard() {
2571 let filter = SchemaFilter::new(vec!["data.**".to_string()]).unwrap();
2572 let matches = filter.get_matching_paths("data.foo.bar");
2573 assert!(!matches.is_empty());
2574 }
2575
2576 #[test]
2577 fn test_schema_filter_path_matches_pattern_single_wildcard() {
2578 let filter = SchemaFilter::new(vec!["user.*.id".to_string()]).unwrap();
2579 let matches = filter.get_matching_paths("user.john.id");
2580 let _ = matches;
2582 }
2583
2584 #[test]
2585 fn test_schema_filter_path_no_match() {
2586 let filter = SchemaFilter::new(vec!["user.name".to_string()]).unwrap();
2587 let matches = filter.get_matching_paths("other.field");
2588 assert!(matches.is_empty());
2589 }
2590
2591 #[test]
2592 fn test_json_path_context_multiple_scopes() {
2593 let paths = FastHashSet::default();
2594 let mut context = JsonPathContext::new(paths);
2595 context.enter_scope("a");
2596 context.enter_scope("b");
2597 context.enter_scope("c");
2598 assert_eq!(context.depth, 3);
2599 assert_eq!(context.current_path(), "a.b.c");
2600 context.exit_scope();
2601 context.exit_scope();
2602 context.exit_scope();
2603 assert_eq!(context.depth, 0);
2604 assert_eq!(context.current_path(), "");
2605 }
2606
2607 #[test]
2608 fn test_json_path_context_should_process_empty() {
2609 let paths = FastHashSet::default();
2610 let context = JsonPathContext::new(paths);
2611 let _ = context.should_process();
2613 }
2614
2615 #[test]
2616 fn test_black_box_processor_read_field_value_types() {
2617 let mut processor = BlackBoxProcessor::new_unfiltered();
2618 processor
2619 .process(
2620 r#"{"str": "hello", "num": 42, "bool": true, "null": null, "obj": {}, "arr": []}"#,
2621 )
2622 .unwrap();
2623
2624 let _ = processor.read_field_value("str");
2626 let _ = processor.read_field_value("num");
2627 let _ = processor.read_field_value("bool");
2628 let _ = processor.read_field_value("null");
2629 let _ = processor.read_field_value("obj");
2630 let _ = processor.read_field_value("arr");
2631 }
2632
2633 #[test]
2634 fn test_black_box_processor_field_add_then_delete() {
2635 let mut processor = BlackBoxProcessor::new_unfiltered();
2636 processor.process(r"{}").unwrap();
2637
2638 processor
2640 .apply_operation(&DsonOperation::FieldAdd {
2641 path: "field".to_string(),
2642 value: OperationValue::StringRef("value".to_string()),
2643 })
2644 .unwrap();
2645 assert!(processor.modifications.contains_key("field"));
2646 assert!(!processor.deletions.contains("field"));
2647
2648 processor
2650 .apply_operation(&DsonOperation::FieldDelete {
2651 path: "field".to_string(),
2652 })
2653 .unwrap();
2654 assert!(!processor.modifications.contains_key("field"));
2655 assert!(processor.deletions.contains("field"));
2656 }
2657
2658 #[test]
2659 fn test_black_box_processor_delete_then_add() {
2660 let mut processor = BlackBoxProcessor::new_unfiltered();
2661 processor.process(r"{}").unwrap();
2662
2663 processor
2665 .apply_operation(&DsonOperation::FieldDelete {
2666 path: "field".to_string(),
2667 })
2668 .unwrap();
2669 assert!(processor.deletions.contains("field"));
2670
2671 processor
2673 .apply_operation(&DsonOperation::FieldAdd {
2674 path: "field".to_string(),
2675 value: OperationValue::StringRef("value".to_string()),
2676 })
2677 .unwrap();
2678 assert!(!processor.deletions.contains("field"));
2679 assert!(processor.modifications.contains_key("field"));
2680 }
2681
2682 #[test]
2683 fn test_process_adaptive_fast_path() {
2684 let mut processor = BlackBoxProcessor::new_unfiltered();
2685 let operations = vec![DsonOperation::FieldAdd {
2687 path: "name".to_string(),
2688 value: OperationValue::StringRef("test".to_string()),
2689 }];
2690 let result = processor.process_adaptive(r#"{"base": "data"}"#, &operations);
2691 assert!(result.is_ok());
2692 }
2693
2694 #[test]
2695 fn test_process_adaptive_balanced_path() {
2696 let mut processor = BlackBoxProcessor::new_unfiltered();
2697 let large_value = "x".repeat(15_000);
2699 let input = format!(r#"{{"data": "{large_value}"}}"#);
2700 let operations = vec![DsonOperation::FieldAdd {
2701 path: "name".to_string(),
2702 value: OperationValue::StringRef("test".to_string()),
2703 }];
2704 let result = processor.process_adaptive(&input, &operations);
2705 assert!(result.is_ok());
2706 }
2707
2708 #[test]
2709 fn test_process_adaptive_memory_efficient_path() {
2710 let mut processor = BlackBoxProcessor::new_unfiltered();
2711 let large_value = "x".repeat(1_100_000);
2713 let input = format!(r#"{{"data": "{large_value}"}}"#);
2714 let operations = vec![DsonOperation::FieldAdd {
2715 path: "name".to_string(),
2716 value: OperationValue::StringRef("test".to_string()),
2717 }];
2718 let result = processor.process_adaptive(&input, &operations);
2719 assert!(result.is_ok());
2720 }
2721
2722 #[test]
2723 fn test_process_adaptive_many_operations() {
2724 let mut processor = BlackBoxProcessor::new_unfiltered();
2725 let mut operations = Vec::new();
2727 for i in 0..150 {
2728 operations.push(DsonOperation::FieldAdd {
2729 path: format!("field{i}"),
2730 value: OperationValue::NumberRef(i.to_string()),
2731 });
2732 }
2733 let result = processor.process_adaptive(r#"{"base": "data"}"#, &operations);
2734 assert!(result.is_ok());
2735 }
2736
2737 #[test]
2738 fn test_determine_processing_mode() {
2739 let processor = BlackBoxProcessor::new_unfiltered();
2740
2741 assert_eq!(
2743 processor.determine_processing_mode(1000, 5),
2744 ProcessingMode::Fast
2745 );
2746
2747 assert_eq!(
2749 processor.determine_processing_mode(2_000_000, 5),
2750 ProcessingMode::MemoryEfficient
2751 );
2752
2753 assert_eq!(
2755 processor.determine_processing_mode(1000, 150),
2756 ProcessingMode::MemoryEfficient
2757 );
2758
2759 assert_eq!(
2761 processor.determine_processing_mode(50_000, 50),
2762 ProcessingMode::Balanced
2763 );
2764 }
2765
2766 #[test]
2767 fn test_process_with_output_filter() {
2768 let mut processor = BlackBoxProcessor::new(
2769 vec![
2770 "user".to_string(),
2771 "user.name".to_string(),
2772 "user.email".to_string(),
2773 ],
2774 vec!["user".to_string(), "user.name".to_string()], );
2776
2777 let input = r#"{"user": {"name": "Alice", "email": "alice@example.com", "age": 30}}"#;
2778 let result = processor.process(input).unwrap();
2779
2780 assert!(result.starts_with('{'));
2782 }
2783
2784 #[test]
2785 fn test_schema_filter_array_with_index() {
2786 let filter = SchemaFilter::new(vec!["items[*]".to_string()]).unwrap();
2788 let matches = filter.get_matching_paths("items[0]");
2790 assert!(matches.contains(&"items[*]".to_string()));
2791 }
2792
2793 #[test]
2794 fn test_schema_filter_specific_array_index_extended() {
2795 let filter = SchemaFilter::new(vec!["items[0]".to_string()]).unwrap();
2796 assert!(filter.matches("items[0]"));
2797 assert!(!filter.matches("items[1]"));
2799 }
2800
2801 #[test]
2802 fn test_schema_filter_nested_wildcard_extended() {
2803 let filter = SchemaFilter::new(vec!["users.*.profile".to_string()]).unwrap();
2804 assert!(filter.matches("users.alice.profile"));
2805 assert!(filter.matches("users.bob.profile"));
2806 }
2807
2808 #[test]
2809 fn test_schema_filter_prefix_via_get_matching() {
2810 let filter = SchemaFilter::new(vec!["user".to_string()]).unwrap();
2811 assert!(filter.matches("user"));
2813 let matches = filter.get_matching_paths("user.name");
2815 assert!(matches.contains(&"user".to_string()));
2816 }
2817
2818 #[test]
2819 fn test_fast_path_field_delete() {
2820 let mut processor = BlackBoxProcessor::new_unfiltered();
2821 let operations = vec![DsonOperation::FieldDelete {
2823 path: "name".to_string(),
2824 }];
2825 let result = processor.process_adaptive(r#"{"name": "Alice", "age": 30}"#, &operations);
2826 assert!(result.is_ok());
2827 let output = result.unwrap();
2828 assert!(!output.contains("Alice"));
2830 assert!(output.contains("30"));
2831 }
2832
2833 #[test]
2834 fn test_fast_path_nested_field_delete() {
2835 let mut processor = BlackBoxProcessor::new_unfiltered();
2836 let operations = vec![DsonOperation::FieldDelete {
2837 path: "user.email".to_string(),
2838 }];
2839 let result = processor.process_adaptive(
2840 r#"{"user": {"name": "Alice", "email": "alice@example.com"}}"#,
2841 &operations,
2842 );
2843 assert!(result.is_ok());
2844 let output = result.unwrap();
2845 assert!(!output.contains("alice@example.com"));
2846 assert!(output.contains("Alice"));
2847 }
2848
2849 #[test]
2850 fn test_fast_path_array_index_delete() {
2851 let mut processor = BlackBoxProcessor::new_unfiltered();
2852 let operations = vec![DsonOperation::FieldDelete {
2853 path: "items[1]".to_string(),
2854 }];
2855 let result = processor.process_adaptive(r#"{"items": ["a", "b", "c"]}"#, &operations);
2856 assert!(result.is_ok());
2857 let output = result.unwrap();
2858 assert!(!output.contains("\"b\""));
2860 }
2861
2862 #[test]
2863 fn test_operation_value_to_json_object_ref() {
2864 let op_value = OperationValue::ObjectRef { start: 0, end: 10 };
2865 let json = BlackBoxProcessor::operation_value_to_json(&op_value);
2866 assert_eq!(json, serde_json::Value::Object(serde_json::Map::new()));
2868 }
2869
2870 #[test]
2871 fn test_operation_value_to_json_array_ref() {
2872 let op_value = OperationValue::ArrayRef { start: 0, end: 10 };
2873 let json = BlackBoxProcessor::operation_value_to_json(&op_value);
2874 assert_eq!(json, serde_json::Value::Array(Vec::new()));
2876 }
2877
2878 #[test]
2879 fn test_process_with_input_schema_filtering() {
2880 let mut processor = BlackBoxProcessor::new(
2881 vec!["user.name".to_string()], vec!["user.name".to_string()],
2883 );
2884
2885 let input = r#"{"user": {"name": "Alice", "email": "alice@example.com"}, "other": "data"}"#;
2886 let result = processor.process(input);
2887 assert!(result.is_ok());
2888 }
2889
2890 #[test]
2891 fn test_memory_efficient_with_schema_filter() {
2892 let mut processor =
2894 BlackBoxProcessor::new(vec!["data".to_string()], vec!["data".to_string()]);
2895
2896 let large_value = "x".repeat(1_100_000);
2898 let input = format!(r#"{{"data": "{large_value}", "other": "ignored"}}"#);
2899
2900 let operations = vec![DsonOperation::FieldAdd {
2901 path: "data.extra".to_string(),
2902 value: OperationValue::StringRef("test".to_string()),
2903 }];
2904
2905 let result = processor.process_adaptive(&input, &operations);
2906 assert!(result.is_ok());
2907 }
2908
2909 #[test]
2910 fn test_processing_mode_debug_all_variants() {
2911 assert_eq!(format!("{:?}", ProcessingMode::Fast), "Fast");
2912 assert_eq!(format!("{:?}", ProcessingMode::Balanced), "Balanced");
2913 assert_eq!(
2914 format!("{:?}", ProcessingMode::MemoryEfficient),
2915 "MemoryEfficient"
2916 );
2917 }
2918
2919 #[test]
2920 fn test_processing_mode_clone_equality() {
2921 let mode = ProcessingMode::Fast;
2922 let cloned = mode;
2923 assert_eq!(mode, cloned);
2924 }
2925
2926 #[test]
2927 fn test_processing_mode_copy_semantics() {
2928 let mode = ProcessingMode::Balanced;
2929 let copied: ProcessingMode = mode;
2930 assert_eq!(mode, copied);
2931 }
2932
2933 #[test]
2934 fn test_fast_path_nested_array_delete() {
2935 let mut processor = BlackBoxProcessor::new_unfiltered();
2936 let operations = vec![DsonOperation::FieldDelete {
2937 path: "data[0].name".to_string(),
2938 }];
2939 let result = processor.process_adaptive(
2940 r#"{"data": [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]}"#,
2941 &operations,
2942 );
2943 assert!(result.is_ok());
2944 }
2945
2946 #[test]
2947 fn test_fast_path_field_add_creates_nested() {
2948 let mut processor = BlackBoxProcessor::new_unfiltered();
2949 let operations = vec![DsonOperation::FieldAdd {
2950 path: "a.b.c".to_string(),
2951 value: OperationValue::StringRef("deep".to_string()),
2952 }];
2953 let result = processor.process_adaptive(r"{}", &operations);
2954 assert!(result.is_ok());
2955 let output = result.unwrap();
2956 assert!(output.contains("deep"));
2957 }
2958
2959 #[test]
2960 fn test_fast_path_array_index_set() {
2961 let mut processor = BlackBoxProcessor::new_unfiltered();
2962 let operations = vec![DsonOperation::FieldModify {
2963 path: "items[5]".to_string(),
2964 value: OperationValue::StringRef("new".to_string()),
2965 }];
2966 let result = processor.process_adaptive(r#"{"items": ["a", "b"]}"#, &operations);
2967 assert!(result.is_ok());
2968 }
2969
2970 #[test]
2971 fn test_schema_filter_invalid_pattern() {
2972 let result = SchemaFilter::new(vec!["valid.path".to_string()]);
2974 assert!(result.is_ok());
2975 }
2976
2977 #[test]
2978 fn test_fast_path_complex_operation_fallback() {
2979 let mut processor = BlackBoxProcessor::new_unfiltered();
2980 let operations = vec![DsonOperation::ArrayFilter {
2982 path: "items".to_string(),
2983 predicate: FilterPredicate::Even,
2984 }];
2985 let result = processor.process_adaptive(r#"{"items": [1, 2, 3, 4, 5]}"#, &operations);
2986 assert!(result.is_ok());
2987 }
2988
2989 #[test]
2990 fn test_json_path_to_regex_array_wildcard() {
2991 let filter = SchemaFilter::new(vec!["items[*]".to_string()]).unwrap();
2993 assert!(filter.paths().contains(&"items[*]".to_string()));
2995 }
2996
2997 #[test]
2998 fn test_json_path_to_regex_specific_index() {
2999 let filter = SchemaFilter::new(vec!["items[0]".to_string()]).unwrap();
3001 assert!(filter.matches("items[0]"));
3002 assert!(!filter.matches("items[1]"));
3003 }
3004
3005 #[test]
3006 fn test_apply_operation_to_value_cached() {
3007 let mut processor = BlackBoxProcessor::new_unfiltered();
3008 processor.process(r#"{"name": "test"}"#).unwrap();
3009
3010 let mut value = serde_json::json!({"name": "test"});
3011 let operation = DsonOperation::FieldModify {
3012 path: "name".to_string(),
3013 value: OperationValue::StringRef("modified".to_string()),
3014 };
3015
3016 let result = processor.apply_operation_to_value_cached(&mut value, &operation);
3017 assert!(result.is_ok());
3018 }
3019
3020 #[test]
3021 fn test_apply_operation_to_value_parsed_field_add() {
3022 let mut processor = BlackBoxProcessor::new_unfiltered();
3023 processor.process(r"{}").unwrap();
3024
3025 let mut value = serde_json::json!({});
3026 let operation = DsonOperation::FieldAdd {
3027 path: "name".to_string(),
3028 value: OperationValue::StringRef("test".to_string()),
3029 };
3030 let parsed = ParsedPath::parse("name");
3031
3032 let result = processor.apply_operation_to_value_parsed(&mut value, &operation, &parsed);
3033 assert!(result.is_ok());
3034 }
3035
3036 #[test]
3037 fn test_apply_operation_to_value_parsed_field_modify() {
3038 let mut processor = BlackBoxProcessor::new_unfiltered();
3039 processor.process(r#"{"name": "old"}"#).unwrap();
3040
3041 let mut value = serde_json::json!({"name": "old"});
3042 let operation = DsonOperation::FieldModify {
3043 path: "name".to_string(),
3044 value: OperationValue::StringRef("new".to_string()),
3045 };
3046 let parsed = ParsedPath::parse("name");
3047
3048 let result = processor.apply_operation_to_value_parsed(&mut value, &operation, &parsed);
3049 assert!(result.is_ok());
3050 }
3051
3052 #[test]
3053 fn test_apply_operation_to_value_parsed_field_delete() {
3054 let mut processor = BlackBoxProcessor::new_unfiltered();
3055 processor.process(r#"{"name": "test"}"#).unwrap();
3056
3057 let mut value = serde_json::json!({"name": "test"});
3058 let operation = DsonOperation::FieldDelete {
3059 path: "name".to_string(),
3060 };
3061 let parsed = ParsedPath::parse("name");
3062
3063 let result = processor.apply_operation_to_value_parsed(&mut value, &operation, &parsed);
3064 assert!(result.is_ok());
3065 }
3066
3067 #[test]
3068 fn test_apply_operation_to_value_parsed_fallback() {
3069 let mut processor = BlackBoxProcessor::new_unfiltered();
3070 processor.process(r#"{"items": [1, 2, 3]}"#).unwrap();
3071
3072 let mut value = serde_json::json!({"items": [1, 2, 3]});
3073 let operation = DsonOperation::ArrayFilter {
3074 path: "items".to_string(),
3075 predicate: FilterPredicate::Even,
3076 };
3077 let parsed = ParsedPath::parse("items");
3078
3079 let result = processor.apply_operation_to_value_parsed(&mut value, &operation, &parsed);
3080 assert!(result.is_ok());
3081 }
3082
3083 #[test]
3084 fn test_output_filtering_array() {
3085 let mut processor = BlackBoxProcessor::new(
3086 vec![
3087 "items".to_string(),
3088 "items[0]".to_string(),
3089 "items[1]".to_string(),
3090 ],
3091 vec!["items".to_string(), "items[0]".to_string()],
3092 );
3093
3094 let input = r#"{"items": [1, 2, 3], "other": "data"}"#;
3095 let result = processor.process(input);
3096 assert!(result.is_ok());
3097 }
3098
3099 #[test]
3100 fn test_extract_i64_from_node() {
3101 let mut processor = BlackBoxProcessor::new_unfiltered();
3102 let result = processor.process(r#"{"value": 9223372036854775807}"#);
3104 assert!(result.is_ok());
3105
3106 let field_value = processor.read_field_value("value");
3108 assert!(field_value.is_ok());
3109 }
3110
3111 #[test]
3112 fn test_extract_f64_from_node() {
3113 let mut processor = BlackBoxProcessor::new_unfiltered();
3114 let result = processor.process(r#"{"value": 3.14159265358979}"#);
3116 assert!(result.is_ok());
3117
3118 let field_value = processor.read_field_value("value");
3120 assert!(field_value.is_ok());
3121 }
3122
3123 #[test]
3124 fn test_set_path_creates_nested_objects() {
3125 let mut processor = BlackBoxProcessor::new_unfiltered();
3126 processor.process(r"{}").unwrap();
3127
3128 let operations = vec![DsonOperation::FieldAdd {
3129 path: "a.b.c.d".to_string(),
3130 value: OperationValue::StringRef("deep".to_string()),
3131 }];
3132
3133 let result = processor.process_with_operations(r"{}", &operations);
3134 assert!(result.is_ok());
3135 let output = result.unwrap();
3136 assert!(output.contains("deep"));
3137 }
3138
3139 #[test]
3140 fn test_set_path_creates_array_elements() {
3141 let mut processor = BlackBoxProcessor::new_unfiltered();
3142 processor.process(r#"{"items": []}"#).unwrap();
3143
3144 let operations = vec![DsonOperation::FieldAdd {
3145 path: "items[0]".to_string(),
3146 value: OperationValue::StringRef("first".to_string()),
3147 }];
3148
3149 let result = processor.process_with_operations(r#"{"items": []}"#, &operations);
3150 assert!(result.is_ok());
3151 }
3152
3153 #[test]
3154 fn test_path_matches_prefix_edge_cases() {
3155 let filter = SchemaFilter::new(vec!["user".to_string(), "users".to_string()]).unwrap();
3156
3157 assert!(filter.matches("user"));
3159 assert!(filter.matches("users"));
3161 let matches = filter.get_matching_paths("username");
3163 assert!(!matches.contains(&"user".to_string()));
3164 }
3165
3166 #[test]
3167 fn test_schema_filter_double_wildcard_extended() {
3168 let filter = SchemaFilter::new(vec!["data.**".to_string()]).unwrap();
3169 let matches = filter.get_matching_paths("data.nested.deep.value");
3170 assert!(matches.contains(&"data.**".to_string()));
3171 }
3172
3173 #[test]
3174 fn test_resolve_field_on_empty_document() {
3175 let mut processor = BlackBoxProcessor::new_unfiltered();
3176 processor.process(r"{}").unwrap();
3178
3179 let result = processor.read_field_value("nonexistent.deep.path");
3181 let _ = result; }
3184
3185 #[test]
3186 fn test_json_path_context_tracking() {
3187 let active_paths = FastHashSet::default();
3188 let mut ctx = JsonPathContext::new(active_paths);
3189
3190 ctx.enter_scope("user");
3191 ctx.enter_scope("profile");
3192 assert_eq!(ctx.current_path(), "user.profile");
3193
3194 ctx.exit_scope();
3195 assert_eq!(ctx.current_path(), "user");
3196
3197 ctx.exit_scope();
3198 assert!(ctx.current_path().is_empty());
3199 }
3200
3201 #[test]
3202 fn test_json_path_context_depth() {
3203 let active_paths = FastHashSet::default();
3204 let mut ctx = JsonPathContext::new(active_paths);
3205
3206 assert_eq!(ctx.depth, 0);
3207
3208 ctx.enter_scope("level1");
3209 assert_eq!(ctx.depth, 1);
3210
3211 ctx.enter_scope("level2");
3212 assert_eq!(ctx.depth, 2);
3213
3214 ctx.exit_scope();
3215 assert_eq!(ctx.depth, 1);
3216 }
3217
3218 #[test]
3219 fn test_apply_output_filtering_object() {
3220 let mut processor = BlackBoxProcessor::new(
3221 vec!["user".to_string(), "user.name".to_string()],
3222 vec!["user".to_string(), "user.name".to_string()],
3223 );
3224
3225 let input = r#"{"user": {"name": "Alice", "email": "alice@example.com"}, "extra": "data"}"#;
3226 let result = processor.process(input);
3227 assert!(result.is_ok());
3228 }
3229
3230 #[test]
3231 fn test_apply_output_filtering_nested_array() {
3232 let mut processor = BlackBoxProcessor::new(
3233 vec![
3234 "data".to_string(),
3235 "data[0]".to_string(),
3236 "data[1]".to_string(),
3237 ],
3238 vec!["data".to_string(), "data[0]".to_string()],
3239 );
3240
3241 let input = r#"{"data": [{"id": 1}, {"id": 2}], "other": "ignored"}"#;
3242 let result = processor.process(input);
3243 assert!(result.is_ok());
3244 }
3245
3246 #[test]
3247 fn test_schema_filter_with_array_pattern() {
3248 let schema = SchemaFilter::new(vec!["data".to_string()]).unwrap();
3250 assert!(schema.matches("data"));
3251 }
3252
3253 #[test]
3254 fn test_schema_filter_with_nested_path() {
3255 let schema = SchemaFilter::new(vec!["users.name".to_string()]).unwrap();
3256 assert!(schema.matches("users.name"));
3257 }
3258
3259 #[test]
3260 fn test_read_field_value_from_modifications() {
3261 let mut processor =
3262 BlackBoxProcessor::new(vec!["name".to_string()], vec!["name".to_string()]);
3263 let input = r#"{"name": "original"}"#;
3264 processor.process(input).unwrap();
3265
3266 let op = DsonOperation::FieldModify {
3268 path: "name".to_string(),
3269 value: OperationValue::StringRef("modified".to_string()),
3270 };
3271 processor.apply_operation(&op).unwrap();
3272
3273 let value = processor.read_field_value("name").unwrap();
3275 assert!(value.is_some());
3276 }
3277
3278 #[test]
3279 fn test_read_field_value_i64() {
3280 let mut processor = BlackBoxProcessor::new_unfiltered();
3281 let input = r#"{"count": -42}"#;
3282 processor.process(input).unwrap();
3283 let value = processor.read_field_value("count").unwrap();
3284 assert!(value.is_some());
3285 }
3286
3287 #[test]
3288 fn test_read_field_value_u64() {
3289 let mut processor = BlackBoxProcessor::new_unfiltered();
3290 let input = r#"{"count": 42}"#;
3291 processor.process(input).unwrap();
3292 let value = processor.read_field_value("count").unwrap();
3293 assert!(value.is_some());
3294 }
3295
3296 #[test]
3297 fn test_read_field_value_f64() {
3298 let mut processor = BlackBoxProcessor::new_unfiltered();
3299 let input = r#"{"pi": 3.14159}"#;
3300 processor.process(input).unwrap();
3301 let value = processor.read_field_value("pi").unwrap();
3302 assert!(value.is_some());
3303 }
3304
3305 #[test]
3306 fn test_read_field_value_null() {
3307 let mut processor = BlackBoxProcessor::new_unfiltered();
3308 let input = r#"{"empty": null}"#;
3309 processor.process(input).unwrap();
3310 let value = processor.read_field_value("empty").unwrap();
3311 assert!(value.is_some());
3312 }
3313
3314 #[test]
3315 fn test_read_field_value_bool() {
3316 let mut processor = BlackBoxProcessor::new_unfiltered();
3317 let input = r#"{"flag": true}"#;
3318 processor.process(input).unwrap();
3319 let value = processor.read_field_value("flag").unwrap();
3320 assert!(value.is_some());
3321 }
3322
3323 #[test]
3324 fn test_read_field_value_object() {
3325 let mut processor = BlackBoxProcessor::new_unfiltered();
3326 let input = r#"{"user": {"name": "test"}}"#;
3327 processor.process(input).unwrap();
3328 let value = processor.read_field_value("user").unwrap();
3329 assert!(value.is_some());
3330 }
3331
3332 #[test]
3333 fn test_read_field_value_array() {
3334 let mut processor = BlackBoxProcessor::new_unfiltered();
3335 let input = r#"{"items": [1, 2, 3]}"#;
3336 processor.process(input).unwrap();
3337 let value = processor.read_field_value("items").unwrap();
3338 assert!(value.is_some());
3339 }
3340
3341 #[test]
3342 fn test_read_field_out_of_bounds() {
3343 let mut processor = BlackBoxProcessor::new_unfiltered();
3344 let input = r#"{"a": 1}"#;
3345 processor.process(input).unwrap();
3346 let value = processor.read_field_value("nonexistent").unwrap();
3347 assert!(value.is_none());
3348 }
3349
3350 #[test]
3351 fn test_output_filtering_with_nested_path() {
3352 let mut processor = BlackBoxProcessor::new(
3353 vec![
3354 "user".to_string(),
3355 "user.profile".to_string(),
3356 "user.profile.name".to_string(),
3357 ],
3358 vec![
3359 "user".to_string(),
3360 "user.profile".to_string(),
3361 "user.profile.name".to_string(),
3362 ],
3363 );
3364 let input = r#"{"user": {"profile": {"name": "test", "age": 30}}}"#;
3365 let result = processor.process(input);
3366 assert!(result.is_ok());
3367 }
3368
3369 #[test]
3370 fn test_output_filtering_array_elements() {
3371 let mut processor = BlackBoxProcessor::new(
3372 vec!["items".to_string(), "items[*]".to_string()],
3373 vec![
3374 "items".to_string(),
3375 "items[0]".to_string(),
3376 "items[1]".to_string(),
3377 ],
3378 );
3379 let input = r#"{"items": [{"a": 1}, {"b": 2}, {"c": 3}]}"#;
3380 let result = processor.process(input);
3381 assert!(result.is_ok());
3382 }
3383
3384 #[test]
3385 fn test_apply_output_filtering_deep_object() {
3386 let mut processor = BlackBoxProcessor::new(
3387 vec![
3388 "root".to_string(),
3389 "root.level1".to_string(),
3390 "root.level1.level2".to_string(),
3391 ],
3392 vec!["root".to_string(), "root.level1".to_string()],
3393 );
3394 let input = r#"{"root": {"level1": {"level2": "value"}, "other": "ignored"}}"#;
3395 let result = processor.process(input);
3396 assert!(result.is_ok());
3397 }
3398}