1use crate::{Edge, Vertex, assert_elements_eq, populate_graph};
2use graph_api_lib::{EdgeReference, EdgeSearch, Graph, VertexSearch};
3
4pub fn test_boxed_simple<T>(graph: &mut T)
5where
6 T: Graph<Vertex = Vertex, Edge = Edge>,
7{
8 let refs = populate_graph(graph);
9
10 let unboxed_result = graph
12 .walk()
13 .vertices_by_id(vec![refs.bryn])
14 .edges(EdgeSearch::scan().outgoing())
15 .head()
16 .collect::<Vec<_>>();
17
18 let boxed_result = graph
19 .walk()
20 .vertices_by_id(vec![refs.bryn])
21 .edges(EdgeSearch::scan().outgoing())
22 .boxed() .head()
24 .collect::<Vec<_>>();
25
26 assert_elements_eq!(
27 graph,
28 unboxed_result.clone(),
29 vec![refs.graph_api, refs.julia]
30 );
31 assert_elements_eq!(graph, boxed_result, vec![refs.graph_api, refs.julia]);
32}
33
34pub fn test_boxed_complex_traversal<T>(graph: &mut T)
35where
36 T: Graph<Vertex = Vertex, Edge = Edge>,
37{
38 let _refs = populate_graph(graph);
39
40 let complex_unboxed_result = graph
43 .walk()
44 .vertices(VertexSearch::scan())
45 .edges(EdgeSearch::scan())
46 .head()
47 .edges(EdgeSearch::scan())
48 .head()
49 .edges(EdgeSearch::scan())
50 .head()
51 .edges(EdgeSearch::scan())
52 .head()
53 .edges(EdgeSearch::scan())
54 .head()
55 .collect::<Vec<_>>();
56
57 let complex_boxed_result = graph
60 .walk()
61 .vertices(VertexSearch::scan())
62 .edges(EdgeSearch::scan())
63 .boxed() .head()
65 .edges(EdgeSearch::scan())
66 .head()
67 .boxed() .edges(EdgeSearch::scan())
69 .head()
70 .edges(EdgeSearch::scan())
71 .boxed() .head()
73 .edges(EdgeSearch::scan())
74 .head()
75 .collect::<Vec<_>>();
76
77 assert_eq!(complex_unboxed_result.len(), complex_boxed_result.len());
79}
80
81pub fn test_boxed_ultra_long_traversal<T>(graph: &mut T)
82where
83 T: Graph<Vertex = Vertex, Edge = Edge>,
84{
85 let _refs = populate_graph(graph);
86
87 let ultra_long_result = graph
92 .walk()
93 .vertices(VertexSearch::scan())
94 .take(2) .edges(EdgeSearch::scan().outgoing()) .boxed() .head()
98 .edges(EdgeSearch::scan().outgoing())
99 .boxed() .head()
101 .edges(EdgeSearch::scan().outgoing())
102 .boxed() .head()
104 .edges(EdgeSearch::scan().outgoing())
105 .boxed() .head()
107 .collect::<Vec<_>>();
108
109 assert!(ultra_long_result.len() < 1_000_000); }
114
115pub fn test_boxed_mixed_operations<T>(graph: &mut T)
116where
117 T: Graph<Vertex = Vertex, Edge = Edge>,
118{
119 let _refs = populate_graph(graph);
120
121 let mixed_result = graph
123 .walk()
124 .vertices(VertexSearch::scan())
125 .take(2)
126 .edges(EdgeSearch::scan())
127 .boxed() .head()
129 .take(1)
130 .edges(EdgeSearch::scan())
131 .boxed() .head()
133 .collect::<Vec<_>>();
134
135 assert!(mixed_result.len() <= 4); }
138
139pub fn test_boxed_edge_walker<T>(graph: &mut T)
140where
141 T: Graph<Vertex = Vertex, Edge = Edge>,
142{
143 let refs = populate_graph(graph);
144
145 let edge_result = graph
147 .walk()
148 .vertices_by_id(vec![refs.bryn])
149 .edges(EdgeSearch::scan().outgoing())
150 .boxed() .collect::<Vec<_>>();
152
153 assert_elements_eq!(
154 graph,
155 edge_result,
156 vec![refs.bryn_knows_julia, refs.bryn_created_graph_api]
157 );
158}
159
160pub fn test_boxed_performance_equivalence<T>(graph: &mut T)
161where
162 T: Graph<Vertex = Vertex, Edge = Edge>,
163{
164 let _refs = populate_graph(graph);
165
166 let unboxed = graph
168 .walk()
169 .vertices(VertexSearch::scan())
170 .edges(EdgeSearch::scan())
171 .head()
172 .edges(EdgeSearch::scan())
173 .head()
174 .take(2)
175 .collect::<Vec<_>>();
176
177 let boxed = graph
178 .walk()
179 .vertices(VertexSearch::scan())
180 .edges(EdgeSearch::scan())
181 .boxed() .head()
183 .edges(EdgeSearch::scan())
184 .head()
185 .take(2)
186 .collect::<Vec<_>>();
187
188 assert_eq!(unboxed.len(), boxed.len());
190 assert!(boxed.len() <= 4); }
192
193pub fn test_boxed_with_context<T>(graph: &mut T)
194where
195 T: Graph<Vertex = Vertex, Edge = Edge>,
196{
197 let refs = populate_graph(graph);
198
199 let result_with_context = graph
202 .walk()
203 .vertices_by_id(vec![refs.bryn])
204 .edges(EdgeSearch::scan().outgoing())
205 .push_context(|edge, _| format!("edge-{:?}", edge.id()))
206 .boxed() .head()
208 .collect::<Vec<_>>();
209
210 assert_elements_eq!(graph, result_with_context, vec![refs.graph_api, refs.julia]);
211}
212
213#[derive(Clone, Debug, PartialEq)]
214struct TestContext {
215 counter: u32,
216 label: String,
217}
218
219pub fn test_boxed_context_delegation<T>(graph: &mut T)
220where
221 T: Graph<Vertex = Vertex, Edge = Edge>,
222{
223 let refs = populate_graph(graph);
224
225 let result = graph
227 .walk()
228 .push_context(TestContext {
229 counter: 0,
230 label: "start".to_string(),
231 })
232 .vertices_by_id(vec![refs.bryn])
233 .mutate_context(|_, ctx| {
234 ctx.counter += 1;
235 ctx.label = "after_vertex".to_string();
236 })
237 .edges(EdgeSearch::scan().outgoing())
238 .boxed() .mutate_context(|_, ctx| {
240 ctx.counter += 10; ctx.label = "after_boxing".to_string();
242 })
243 .head()
244 .map(|vertex, context| {
245 assert_eq!(
247 context.counter, 11,
248 "Context counter should be 0 + 1 + 10 = 11"
249 );
250 assert_eq!(
251 context.label, "after_boxing",
252 "Context label should be updated after boxing"
253 );
254 vertex
255 })
256 .collect::<Vec<_>>();
257
258 assert_eq!(result.len(), 2); }
260
261pub fn test_boxed_context_access_before_next<T>(graph: &mut T)
262where
263 T: Graph<Vertex = Vertex, Edge = Edge>,
264{
265 let refs = populate_graph(graph);
266 let result = graph
268 .walk()
269 .push_context(TestContext {
270 counter: 42,
271 label: "initial".to_string(),
272 })
273 .vertices_by_id(vec![refs.bryn])
274 .edges(EdgeSearch::scan().outgoing())
275 .boxed() .mutate_context(|_, ctx| {
277 assert_eq!(ctx.counter, 42, "Initial context should be preserved");
279 assert_eq!(
280 ctx.label, "initial",
281 "Initial context label should be preserved"
282 );
283 ctx.counter = 100;
284 ctx.label = "modified_after_boxing".to_string();
285 })
286 .head()
287 .map(|vertex, context| {
288 assert_eq!(context.counter, 100, "Context should be modified to 100");
290 assert_eq!(
291 context.label, "modified_after_boxing",
292 "Context label should be updated"
293 );
294 vertex
295 })
296 .collect::<Vec<_>>();
297
298 assert_eq!(result.len(), 2); }
300
301pub fn test_boxed_nested_contexts<T>(graph: &mut T)
302where
303 T: Graph<Vertex = Vertex, Edge = Edge>,
304{
305 let refs = populate_graph(graph);
306
307 let result = graph
309 .walk()
310 .push_context("outer")
311 .vertices_by_id(vec![refs.bryn])
312 .push_context(|_, parent_ctx| format!("inner-{}", parent_ctx))
313 .edges(EdgeSearch::scan().outgoing())
314 .boxed() .head()
316 .map(|vertex, context| {
317 assert_eq!(
319 *context, "inner-outer",
320 "Nested context should combine properly"
321 );
322 assert_eq!(
323 *context.parent(),
324 "outer",
325 "Parent context should be accessible"
326 );
327 vertex
328 })
329 .collect::<Vec<_>>();
330
331 assert_eq!(result.len(), 2); }
333
334pub fn test_boxed_context_persistence<T>(graph: &mut T)
335where
336 T: Graph<Vertex = Vertex, Edge = Edge>,
337{
338 let refs = populate_graph(graph);
339
340 let result = graph
343 .walk()
344 .push_context(TestContext {
345 counter: 5,
346 label: "original".to_string(),
347 })
348 .vertices_by_id(vec![refs.bryn, refs.julia])
349 .boxed() .mutate_context(|_, ctx| {
351 assert_eq!(ctx.counter, 5, "Counter should start at 5");
353 assert_eq!(ctx.label, "original", "Label should start as 'original'");
354
355 ctx.label = "modified_by_mutate_context".to_string();
357 ctx.counter = 42;
358 })
359 .map(|vertex, context| {
360 assert_eq!(context.counter, 42, "Counter should be modified to 42");
362 assert_eq!(
363 context.label, "modified_by_mutate_context",
364 "Label should be updated"
365 );
366 vertex
367 })
368 .collect::<Vec<_>>();
369
370 assert_eq!(result.len(), 2); }