1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//! Tests for Pattern::filter operation
//!
//! This module tests the filter operation which extracts all subpatterns
//! (including root) that satisfy a given pattern predicate.
use pattern_core::Pattern;
#[test]
fn test_filter_atomic_patterns_only() {
// T043: filter with predicate matching atomic patterns only
let pat = Pattern::pattern(
"root",
vec![
Pattern::point("leaf1"),
Pattern::pattern("branch", vec![Pattern::point("leaf2")]),
Pattern::point("leaf3"),
],
);
let atomics = pat.filter(|p| p.is_atomic());
// Should find leaf1, leaf2, leaf3
assert_eq!(atomics.len(), 3);
assert!(atomics.iter().all(|p| p.is_atomic()));
}
#[test]
fn test_filter_root_pattern_matches() {
// T044: filter with predicate matching root pattern
let pat = Pattern::pattern("root", vec![Pattern::point("leaf")]);
let matches = pat.filter(|p| p.value == "root");
// Should find root pattern
assert_eq!(matches.len(), 1);
assert_eq!(matches[0].value, "root");
}
#[test]
fn test_filter_no_matches() {
// T045: filter with predicate matching no patterns (empty result)
let pat = Pattern::pattern(5, vec![Pattern::point(10), Pattern::point(3)]);
let matches = pat.filter(|p| p.value > 100);
// Should find no matches
assert_eq!(matches.len(), 0);
}
#[test]
fn test_filter_all_patterns() {
// T046: filter with predicate matching all patterns (const true)
let pat = Pattern::pattern(
5,
vec![
Pattern::point(10),
Pattern::pattern(3, vec![Pattern::point(15)]),
],
);
let matches = pat.filter(|_| true);
// Should find all 4 patterns: root(5), point(10), pattern(3), point(15)
assert_eq!(matches.len(), 4);
}
#[test]
fn test_filter_complex_structural_predicate() {
// T047: filter with complex structural predicate (length > 0 && depth < 3)
let pat = Pattern::pattern(
"root",
vec![
Pattern::point("leaf1"),
Pattern::pattern("branch", vec![Pattern::point("leaf2")]),
Pattern::pattern(
"deep",
vec![Pattern::pattern("deeper", vec![Pattern::point("leaf3")])],
),
],
);
let matches = pat.filter(|p| p.length() > 0 && p.depth() < 3);
// Should find: root (length=3, depth=3), branch (length=1, depth=1)
// Not: deep (depth=3), deeper (length=1, depth=1 but inside deep structure)
// Actually, let's be clearer: patterns with elements AND not too deep themselves
assert!(matches.len() >= 2);
assert!(matches.iter().all(|p| p.length() > 0 && p.depth() < 3));
}
#[test]
fn test_filter_structural_and_value_predicate() {
// T048: filter with predicates combining structural and value properties
let pat = Pattern::pattern(
10,
vec![
Pattern::point(5),
Pattern::pattern(20, vec![Pattern::point(3)]),
Pattern::pattern(15, vec![]),
],
);
let matches = pat.filter(|p| p.value > 10 && p.length() > 0);
// Should find: pattern(20, [point(3)]) - value > 10 and has elements
// Not: pattern(15, []) - length is 0
assert_eq!(matches.len(), 1);
assert_eq!(matches[0].value, 20);
}
#[test]
fn test_filter_pre_order_traversal() {
// T049: filter returns results in pre-order traversal order
let pat = Pattern::pattern(
1,
vec![
Pattern::point(2),
Pattern::pattern(3, vec![Pattern::point(4)]),
Pattern::point(5),
],
);
let all_matches = pat.filter(|_| true);
// Pre-order: 1, 2, 3, 4, 5
assert_eq!(all_matches.len(), 5);
assert_eq!(all_matches[0].value, 1); // root
assert_eq!(all_matches[1].value, 2); // first element
assert_eq!(all_matches[2].value, 3); // second element (pattern)
assert_eq!(all_matches[3].value, 4); // nested in second element
assert_eq!(all_matches[4].value, 5); // third element
}
#[test]
fn test_filter_deeply_nested() {
// T050: filter with deeply nested pattern (100+ levels)
fn create_deep_pattern(depth: usize, value: i32) -> Pattern<i32> {
if depth == 0 {
Pattern::point(value)
} else {
Pattern::pattern(value, vec![create_deep_pattern(depth - 1, value + 1)])
}
}
let deep_pat = create_deep_pattern(150, 0);
// Find all patterns with even values
let even_matches = deep_pat.filter(|p| p.value % 2 == 0);
// Values are 0, 1, 2, ..., 150
// Even values: 0, 2, 4, ..., 150 = 76 values
assert_eq!(even_matches.len(), 76);
assert!(even_matches.iter().all(|p| p.value % 2 == 0));
}
#[test]
fn test_filter_large_flat_pattern() {
// T051: filter with large flat pattern (1000+ elements)
let elements: Vec<Pattern<i32>> = (0..1000).map(|i| Pattern::point(i)).collect();
let pat = Pattern::pattern(999, elements);
// Find patterns with values > 500
let high_value_matches = pat.filter(|p| p.value > 500);
// Should find: 501, 502, ..., 999 (elements) + 999 (root) if > 500
// Root value is 999, so it matches
// Elements 501-999 = 499 elements
// Total: 1 (root) + 499 (elements) = 500
assert_eq!(high_value_matches.len(), 500);
assert!(high_value_matches.iter().all(|p| p.value > 500));
}
#[test]
fn test_filter_returns_references() {
// Additional test: Verify filter returns references, not clones
let pat = Pattern::pattern("root", vec![Pattern::point("leaf")]);
let matches = pat.filter(|_| true);
// Should be references to patterns in original structure
assert_eq!(matches.len(), 2);
// Verify they point to the actual pattern structure
assert!(std::ptr::eq(matches[0], &pat));
assert!(std::ptr::eq(matches[1], &pat.elements[0]));
}