mod common;
use std::time::Instant;
use dcbor_parse::parse_dcbor_item;
use dcbor_pattern::{Matcher, Pattern, format_paths};
use indoc::indoc;
#[test]
fn test_deeply_nested_performance() {
let start = Instant::now();
#[rustfmt::skip]
let pattern = Pattern::parse(r#"
tagged(100, {"a": {"b": {"c": {"d": [42]}}}})
"#).unwrap();
let pattern_creation_time = start.elapsed();
let data =
parse_dcbor_item(r#"100({"a": {"b": {"c": {"d": [42]}}}})"#).unwrap();
let match_start = Instant::now();
let result = pattern.matches(&data);
let match_time = match_start.elapsed();
assert!(result, "Should match deeply nested structure");
let paths_start = Instant::now();
let paths = pattern.paths(&data);
let paths_time = paths_start.elapsed();
#[rustfmt::skip]
let expected = indoc! {r#"
100({"a": {"b": {"c": {"d": [42]}}}})
"#}.trim();
assert_actual_expected!(format_paths(&paths), expected);
assert!(
pattern_creation_time.as_millis() < 10,
"Pattern creation should be fast"
);
assert!(
match_time.as_millis() < 10,
"Pattern matching should be fast"
);
assert!(
paths_time.as_millis() < 10,
"Path generation should be fast"
);
println!(
"Deep nesting performance - Pattern creation: {:?}, Matching: {:?}, Paths: {:?}",
pattern_creation_time, match_time, paths_time
);
}
#[test]
fn test_complex_repeat_pattern_performance() {
let start = Instant::now();
#[rustfmt::skip]
let pattern = Pattern::parse(r#"
[({"id": number})*, (*)*, ({"name": text})*]
"#).unwrap();
let pattern_creation_time = start.elapsed();
let data = parse_dcbor_item(r#"[{"id": 1}, {"id": 2}, 42, "test", true, {"name": "Alice"}, {"name": "Bob"}]"#).unwrap();
let match_start = Instant::now();
let result = pattern.matches(&data);
let match_time = match_start.elapsed();
assert!(result, "Should match complex pattern with multiple repeats");
let paths_start = Instant::now();
let paths = pattern.paths(&data);
let paths_time = paths_start.elapsed();
#[rustfmt::skip]
let expected = indoc! {r#"
[{"id": 1}, {"id": 2}, 42, "test", true, {"name": "Alice"}, {"name": "Bob"}]
"#}.trim();
assert_actual_expected!(format_paths(&paths), expected);
assert!(
pattern_creation_time.as_millis() < 10,
"Complex pattern creation should be fast"
);
assert!(
match_time.as_millis() < 10,
"Complex pattern matching should be fast"
);
assert!(
paths_time.as_millis() < 10,
"Complex path generation should be fast"
);
println!(
"Complex repeat performance - Pattern creation: {:?}, Matching: {:?}, Paths: {:?}",
pattern_creation_time, match_time, paths_time
);
}
#[test]
fn test_large_array_with_search_performance() {
let start = Instant::now();
#[rustfmt::skip]
let pattern = Pattern::parse(r#"
search("needle")
"#).unwrap();
let pattern_creation_time = start.elapsed();
let large_data = parse_dcbor_item(
r#"[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
{"a": 1}, {"b": 2}, {"c": 3}, {"d": 4}, {"e": 5},
[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12],
"needle",
{"final": true}
]"#,
)
.unwrap();
let match_start = Instant::now();
let result = pattern.matches(&large_data);
let match_time = match_start.elapsed();
assert!(result, "Should find needle in large structure");
let paths_start = Instant::now();
let paths = pattern.paths(&large_data);
let paths_time = paths_start.elapsed();
#[rustfmt::skip]
let expected = indoc! {r#"
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, {"a": 1}, {"b": 2}, {"c": 3}, {"d": 4}, {"e": 5}, [1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], "needle", {"final": true}]
"needle"
"#}.trim();
assert_actual_expected!(format_paths(&paths), expected);
assert!(
pattern_creation_time.as_millis() < 10,
"Search pattern creation should be fast"
);
assert!(
match_time.as_millis() < 20,
"Search through large structure should be reasonably fast"
);
assert!(
paths_time.as_millis() < 10,
"Path generation should be fast"
);
println!(
"Large structure search performance - Pattern creation: {:?}, Matching: {:?}, Paths: {:?}",
pattern_creation_time, match_time, paths_time
);
}
#[test]
fn test_complex_or_pattern_performance() {
let start = Instant::now();
#[rustfmt::skip]
let pattern = Pattern::parse(r#"
tagged(1, number) |
tagged(2, text) |
tagged(3, [number]) |
tagged(4, {text: *}) |
tagged(5, bool) |
{"type": "user"} |
{"type": "admin"} |
["start"] |
[number, text, bool]
"#).unwrap();
let pattern_creation_time = start.elapsed();
let data = parse_dcbor_item(r#"[42, "test", true]"#).unwrap();
let match_start = Instant::now();
let result = pattern.matches(&data);
let match_time = match_start.elapsed();
assert!(result, "Should match complex OR pattern");
let paths_start = Instant::now();
let paths = pattern.paths(&data);
let paths_time = paths_start.elapsed();
#[rustfmt::skip]
let expected = indoc! {r#"
[42, "test", true]
"#}.trim();
assert_actual_expected!(format_paths(&paths), expected);
assert!(
pattern_creation_time.as_millis() < 10,
"Complex OR pattern creation should be fast"
);
assert!(
match_time.as_millis() < 10,
"Complex OR pattern matching should be fast"
);
assert!(
paths_time.as_millis() < 10,
"Path generation should be fast"
);
println!(
"Complex OR performance - Pattern creation: {:?}, Matching: {:?}, Paths: {:?}",
pattern_creation_time, match_time, paths_time
);
}
#[test]
fn test_vm_instruction_optimization() {
#[rustfmt::skip]
let pattern = Pattern::parse(r#"
tagged(100, [
({"key": number})*, "separator", ({"value": text})*
])
"#).unwrap();
let test_cases = vec![
r#"100(["separator"])"#,
r#"100([{"key": 1}, "separator"])"#,
r#"100(["separator", {"value": "test"}])"#,
r#"100([{"key": 1}, {"key": 2}, "separator", {"value": "a"}, {"value": "b"}])"#,
];
let total_start = Instant::now();
for test_case in test_cases {
let data = parse_dcbor_item(test_case).unwrap();
let result = pattern.matches(&data);
assert!(result, "Should match test case: {}", test_case);
let paths = pattern.paths(&data);
assert!(
!paths.is_empty(),
"Should generate paths for test case: {}",
test_case
);
}
let total_time = total_start.elapsed();
assert!(
total_time.as_millis() < 20,
"VM optimization should enable fast repeated matching"
);
}
#[test]
fn test_edge_case_performance() {
#[rustfmt::skip]
let pattern = Pattern::parse(r#"
[(*)*]
"#).unwrap();
let large_array = parse_dcbor_item(
r#"[
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
true, false, null,
"more", "strings", "here"
]"#,
)
.unwrap();
let start = Instant::now();
let result = pattern.matches(&large_array);
let elapsed = start.elapsed();
assert!(result, "Should match large array with * repeat pattern");
let paths_start = Instant::now();
let paths = pattern.paths(&large_array);
let paths_time = paths_start.elapsed();
#[rustfmt::skip]
let expected = indoc! {r#"
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, true, false, null, "more", "strings", "here"]
"#}.trim();
assert_actual_expected!(format_paths(&paths), expected);
assert!(
elapsed.as_millis() < 50,
"* repeat patterns should not cause exponential behavior"
);
assert!(
paths_time.as_millis() < 50,
"Path generation should not cause exponential behavior"
);
println!(
"Edge case performance - * repeats on large array: {:?}, Paths: {:?}",
elapsed, paths_time
);
}