mod common;
use bc_envelope::prelude::*;
use bc_envelope_pattern::{Matcher, Pattern, format_paths};
use dcbor_parse::parse_dcbor_item;
use indoc::indoc;
#[test]
fn test_cbor_pattern_simple_array_paths() {
let array_data = vec![1, 2, 3];
let envelope = Envelope::new(array_data);
let pattern = Pattern::parse("cbor(/search(number)/)").unwrap();
let paths = pattern.paths(&envelope);
let actual = format_paths(&paths);
#[rustfmt::skip]
let expected = indoc! {r#"
4abc3113 LEAF [1, 2, 3]
4bf5122f LEAF 1
4abc3113 LEAF [1, 2, 3]
dbc1b4c9 LEAF 2
4abc3113 LEAF [1, 2, 3]
084fed08 LEAF 3
"#}
.trim();
assert_actual_expected!(
actual,
expected,
"`cbor` pattern should return extended paths for array elements"
);
}
#[test]
fn test_cbor_pattern_nested_structure_paths() {
let nested_cbor =
parse_dcbor_item(r#"{"scores": [95, 87, 92], "value": 42}"#).unwrap();
let envelope = Envelope::new(nested_cbor);
let pattern = Pattern::parse("cbor(/search(number)/)").unwrap();
let paths = pattern.paths(&envelope);
assert_eq!(
paths.len(),
4,
"Should find 4 numbers in the nested structure"
);
for (i, path) in paths.iter().enumerate() {
assert_eq!(
path[0], envelope,
"Path {} should start with root envelope",
i
);
assert!(path.len() > 1, "Path {} should be extended beyond root", i);
}
}
#[test]
fn test_cbor_pattern_single_value_paths() {
let envelope = Envelope::new(42);
let pattern = Pattern::parse("cbor(/number/)").unwrap();
let paths = pattern.paths(&envelope);
let actual = format_paths(&paths);
let expected = "7f83f7bd LEAF 42";
assert_actual_expected!(
actual,
expected,
"Single value `cbor` pattern should return just the root envelope"
);
}
#[test]
fn test_cbor_pattern_text_search_paths() {
let cbor_data = parse_dcbor_item(
r#"{"name": "Alice", "items": ["apple", "banana"], "count": 2}"#,
)
.unwrap();
let envelope = Envelope::new(cbor_data);
let pattern = Pattern::parse("cbor(/search(text)/)").unwrap();
let paths = pattern.paths(&envelope);
assert_eq!(
paths.len(),
6,
"Should find 6 text values including map keys"
);
for path in &paths {
assert_eq!(
path[0], envelope,
"Each path should start with root envelope"
);
assert!(path.len() > 1, "Each path should be extended beyond root");
let last_element = path.last().unwrap();
if let Some(cbor) = last_element.as_leaf() {
assert!(
matches!(cbor.as_case(), dcbor::CBORCase::Text(_)),
"Last element should be text `cbor`"
);
}
}
}
#[test]
fn test_cbor_pattern_no_matches_paths() {
let envelope = Envelope::new("just text");
let pattern = Pattern::parse("cbor(/number/)").unwrap();
let paths = pattern.paths(&envelope);
let actual = format_paths(&paths);
let expected = "";
assert_actual_expected!(
actual,
expected,
"Pattern with no matches should return empty paths"
);
}
#[test]
fn test_cbor_pattern_paths_preserve_order() {
let array_cbor = parse_dcbor_item("[10, 20, 30]").unwrap();
let envelope = Envelope::new(array_cbor);
let pattern = Pattern::parse("cbor(/search(number)/)").unwrap();
let paths = pattern.paths(&envelope);
assert_eq!(paths.len(), 3, "Should find 3 numbers");
let mut found_numbers = Vec::new();
for path in &paths {
if let Some(last_element) = path.last()
&& let Some(cbor) = last_element.as_leaf()
&& let dcbor::CBORCase::Unsigned(n) = cbor.as_case()
{
found_numbers.push(*n);
}
}
assert_eq!(
found_numbers,
vec![10, 20, 30],
"Numbers should be found in dcbor-pattern order"
);
}
#[test]
fn test_cbor_pattern_complex_nested_paths() {
let complex_cbor = parse_dcbor_item(
r#"
{
"users": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
],
"total": 2
}
"#,
)
.unwrap();
let envelope = Envelope::new(complex_cbor);
let pattern = Pattern::parse("cbor(/search(number)/)").unwrap();
let paths = pattern.paths(&envelope);
assert_eq!(paths.len(), 3, "Should find 3 numbers in complex structure");
let path_lengths: Vec<usize> = paths.iter().map(|p| p.len()).collect();
for &length in &path_lengths {
assert!(
length > 1,
"All paths should be extended beyond root envelope"
);
}
}