1pub extern crate proptest;
2pub use proptest::*;
3pub mod fuzz;
4pub mod graph;
5pub mod index;
6pub mod steps;
7
8use graph_api_derive::{EdgeExt, VertexExt};
9use graph_api_lib::ElementId;
10#[allow(unused_imports)]
11use graph_api_lib::{
12 SupportsClear, SupportsEdgeAdjacentLabelIndex, SupportsEdgeHashIndex, SupportsEdgeLabelIndex,
13 SupportsEdgeRangeIndex, SupportsVertexFullTextIndex, SupportsVertexHashIndex,
14 SupportsVertexLabelIndex, SupportsVertexRangeIndex,
15};
16use std::collections::HashSet;
17use std::fmt::{Debug, Display, Formatter};
18use thiserror::Error;
19use uuid::Uuid;
20
21#[derive(Debug, Clone, VertexExt)]
22pub enum Vertex {
23 Person {
24 #[index(hash)]
25 name: String,
26 #[index(range)]
27 age: u64,
28 #[index(hash)]
29 unique_id: Uuid,
30 #[index(range)]
31 username: String,
32 #[index(full_text)]
33 biography: String,
34 },
35 Project(Project),
36 Rust,
37}
38
39#[derive(Debug, Clone)]
40pub struct Project {
41 pub name: String,
42}
43
44#[derive(Debug, Clone, EdgeExt)]
45pub enum Edge {
46 Knows { since: i32 },
47 Created,
48 Language(Language),
49}
50#[derive(Debug, Clone)]
51pub struct Language {
52 pub name: String,
53}
54pub struct Refs<Graph>
55where
56 Graph: graph_api_lib::Graph,
57{
58 pub bryn: Graph::VertexId,
59 pub julia: Graph::VertexId,
60 pub graph_api: Graph::VertexId,
61 pub rust: Graph::VertexId,
62 pub bryn_knows_julia: Graph::EdgeId,
63 pub julia_knows_bryn: Graph::EdgeId,
64 pub bryn_created_graph_api: Graph::EdgeId,
65 pub graph_api_language_rust: Graph::EdgeId,
66}
67
68pub fn populate_graph<Graph>(graph: &mut Graph) -> Refs<Graph>
69where
70 Graph: graph_api_lib::Graph<Vertex = Vertex, Edge = Edge>,
71{
72 let bryn = graph.add_vertex(Vertex::Person {
74 name: "Bryn".to_string(),
75 age: 45,
76 unique_id: Uuid::from_u128(1),
77 username: "bryn".to_string(),
78 biography: "Did some graph stuff".to_string(),
79 });
80 let julia = graph.add_vertex(Vertex::Person {
81 name: "Julia".to_string(),
82 age: 48,
83 unique_id: Uuid::from_u128(2),
84 username: "julia".to_string(),
85 biography: "Mastered the English language".to_string(),
86 });
87 let graph_api = graph.add_vertex(Vertex::Project(Project {
88 name: "GraphApi".to_string(),
89 }));
90
91 let rust = graph.add_vertex(Vertex::Rust);
92
93 let bryn_knows_julia = graph.add_edge(bryn, julia, Edge::Knows { since: 1999 });
94 let julia_knows_bryn = graph.add_edge(julia, bryn, Edge::Knows { since: 1999 });
95 let bryn_created_graph_api = graph.add_edge(bryn, graph_api, Edge::Created);
96 let graph_api_language_rust = graph.add_edge(
97 graph_api,
98 rust,
99 Edge::Language(Language {
100 name: "Rust".to_string(),
101 }),
102 );
103
104 Refs {
105 bryn,
106 julia,
107 graph_api,
108 rust,
109 bryn_knows_julia,
110 julia_knows_bryn,
111 bryn_created_graph_api,
112 graph_api_language_rust,
113 }
114}
115
116#[derive(Error, Debug)]
117pub enum TestError {
118 Mismatch {
119 missing: Vec<String>,
120 extra: Vec<String>,
121 expected: Vec<String>,
122 },
123 MoreThanOneElement {
124 expected: Vec<String>,
125 actual: Vec<String>,
126 },
127}
128
129#[macro_export]
130macro_rules! general_test {
131 ($setup:expr, $name:ident, $path:path) => {
132 #[test]
133 fn $name() {
134 let mut g = $setup;
135 $path(&mut g);
136 }
137 };
138}
139
140#[macro_export]
141macro_rules! test_suite {
142 ($setup:expr) => {
143 $crate::general_test!{$setup, graph_test_add_vertex, $crate::graph::test_add_vertex}
144 $crate::general_test!{$setup, graph_test_mutate_vertex, $crate::graph::test_mutate_vertex}
145 $crate::general_test!{$setup, graph_test_remove_vertex, $crate::graph::test_remove_vertex}
146 $crate::general_test!{$setup, graph_test_add_edge, $crate::graph::test_add_edge}
147 $crate::general_test!{$setup, graph_test_mutate_edge, $crate::graph::test_mutate_edge}
148 $crate::general_test!{$setup, graph_test_remove_edge, $crate::graph::test_remove_edge}
149 $crate::general_test!{$setup, graph_test_remove_vertex_with_edges, $crate::graph::test_remove_vertex_with_edges}
150 $crate::general_test!{$setup, boxed_test_simple, $crate::steps::boxed::test_boxed_simple}
151 $crate::general_test!{$setup, boxed_test_complex_traversal, $crate::steps::boxed::test_boxed_complex_traversal}
152 $crate::general_test!{$setup, boxed_test_ultra_long_traversal, $crate::steps::boxed::test_boxed_ultra_long_traversal}
153 $crate::general_test!{$setup, boxed_test_mixed_operations, $crate::steps::boxed::test_boxed_mixed_operations}
154 $crate::general_test!{$setup, boxed_test_edge_walker, $crate::steps::boxed::test_boxed_edge_walker}
155 $crate::general_test!{$setup, boxed_test_performance_equivalence, $crate::steps::boxed::test_boxed_performance_equivalence}
156 $crate::general_test!{$setup, boxed_test_with_context, $crate::steps::boxed::test_boxed_with_context}
157 $crate::general_test!{$setup, filter_test_vertices_filter, $crate::steps::filter::test_vertices_filter}
158 $crate::general_test!{$setup, filter_test_edges_filter, $crate::steps::filter::test_edges_filter}
159 $crate::general_test!{$setup, vertices_test_vertices_collect, $crate::steps::collect::test_vertices_collect}
160 $crate::general_test!{$setup, vertices_test_edges_collect, $crate::steps::collect::test_edges_collect}
161 $crate::general_test!{$setup, edges_test_out_edges, $crate::steps::edges::test_out_edges}
162 $crate::general_test!{$setup, edges_test_out_edges_limit, $crate::steps::edges::test_out_edges_limit}
163 $crate::general_test!{$setup, edges_test_in_edges, $crate::steps::edges::test_in_edges}
164 $crate::general_test!{$setup, edges_test_in_edges_limit, $crate::steps::edges::test_in_edges_limit}
165 $crate::general_test!{$setup, edges_test_all_edges, $crate::steps::edges::test_all_edges}
166 $crate::general_test!{$setup, edges_test_all_edges_limit, $crate::steps::edges::test_all_edges_limit}
167 $crate::general_test!{$setup, edges_test_out_edges_filtered, $crate::steps::edges::test_out_edges_filtered}
168 $crate::general_test!{$setup, edges_test_out_edges_filtered_limit, $crate::steps::edges::test_out_edges_filtered_limit}
169 $crate::general_test!{$setup, edges_test_in_edges_filtered, $crate::steps::edges::test_in_edges_filtered}
170 $crate::general_test!{$setup, edges_test_in_edges_filtered_limit, $crate::steps::edges::test_in_edges_filtered_limit}
171 $crate::general_test!{$setup, edges_test_all_edges_filtered, $crate::steps::edges::test_all_edges_filtered}
172 $crate::general_test!{$setup, edges_test_all_edges_filtered_limit, $crate::steps::edges::test_all_edges_filtered_limit}
173 $crate::general_test!{$setup, context_test_vertices_context, $crate::steps::context::test_vertices_context}
174 $crate::general_test!{$setup, vertices_test_take, $crate::steps::vertices::test_take}
175 $crate::general_test!{$setup, vertices_test_head, $crate::steps::vertices::test_head}
176 $crate::general_test!{$setup, vertices_test_tail, $crate::steps::vertices::test_tail}
177 $crate::general_test!{$setup, mutate_context_vertex, $crate::steps::mutate_context::test_vertex_mutate_context}
178 $crate::general_test!{$setup, mutate_context_edge, $crate::steps::mutate_context::test_edge_mutate_context}
179 $crate::general_test!{$setup, mutation_test_mutation, $crate::steps::mutation::test_mutation}
180 $crate::general_test!{$setup, mutation_test_edge_mutation, $crate::steps::mutation::test_edge_mutation}
181 $crate::general_test!{$setup, count_test_vertices_count, $crate::steps::count::test_vertices_count}
182 $crate::general_test!{$setup, count_test_edges_count, $crate::steps::count::test_edges_count}
183 $crate::general_test!{$setup, take_test_vertices_take, $crate::steps::take::test_vertices_take}
184 $crate::general_test!{$setup, take_test_edges_take, $crate::steps::take::test_edges_take}
185 $crate::general_test!{$setup, first_test_vertices_first, $crate::steps::first::test_vertices_first}
186 $crate::general_test!{$setup, first_test_edges_first, $crate::steps::first::test_edges_first}
187 $crate::general_test!{$setup, fold_test_vertices_fold, $crate::steps::fold::test_vertices_fold}
188 $crate::general_test!{$setup, fold_test_edges_fold, $crate::steps::fold::test_edges_fold}
189 $crate::general_test!{$setup, reduce_test_vertices_reduce, $crate::steps::reduce::test_vertices_reduce}
190 $crate::general_test!{$setup, reduce_test_edges_reduce, $crate::steps::reduce::test_edges_reduce}
191 $crate::general_test!{$setup, detour_test_vertices_detour, $crate::steps::detour::test_vertices_detour}
192 $crate::general_test!{$setup, filter_derive_test_vertices_filter, $crate::steps::filter_derive::test_vertices_filter}
193 $crate::general_test!{$setup, filter_derive_test_edges_filter, $crate::steps::filter_derive::test_edges_filter}
194 $crate::general_test!{$setup, probe_test_vertices_probe, $crate::steps::probe::test_vertices_probe}
195 $crate::general_test!{$setup, probe_test_edges_probe, $crate::steps::probe::test_edges_probe}
196 $crate::general_test!{$setup, control_flow_test_vertices_control_flow, $crate::steps::control_flow::test_vertices_control_flow}
197 $crate::general_test!{$setup, control_flow_test_edges_control_flow, $crate::steps::control_flow::test_edges_control_flow}
198 $crate::general_test!{$setup, index_edge_label_test_index, $crate::index::edge_label::test_index}
199 $crate::general_test!{$setup, index_edge_label_test_index_limit, $crate::index::edge_label::test_index_limit}
200 $crate::general_test!{$setup, index_vertex_label_test_index, $crate::index::vertex_label::test_index}
201 $crate::general_test!{$setup, index_vertex_label_test_index_limit, $crate::index::vertex_label::test_index_limit}
202 $crate::general_test!{$setup, index_vertex_hash_test_index, $crate::index::vertex_hash::test_index}
203 $crate::general_test!{$setup, index_vertex_hash_test_index_remove, $crate::index::vertex_hash::test_index_remove}
204 $crate::general_test!{$setup, index_vertex_hash_test_index_update, $crate::index::vertex_hash::test_index_update}
205 $crate::general_test!{$setup, index_vertex_full_text_test_index, $crate::index::vertex_full_text::test_index}
206 $crate::general_test!{$setup, index_vertex_full_text_test_index_remove, $crate::index::vertex_full_text::test_index_remove}
207 $crate::general_test!{$setup, index_vertex_full_text_test_index_update, $crate::index::vertex_full_text::test_index_update}
208 $crate::general_test!{$setup, index_vertex_range_test_index, $crate::index::vertex_range::test_index}
209 $crate::general_test!{$setup, index_vertex_range_test_index_remove, $crate::index::vertex_range::test_index_remove}
210 $crate::general_test!{$setup, index_vertex_range_test_index_update, $crate::index::vertex_range::test_index_update}
211
212 $crate::proptest! {
213 #[test]
214 fn fuzz_test(operations in $crate::collection::vec($crate::fuzz::arb_graph_operation(), 0..100)) {
215 $crate::fuzz::test_fuzz($setup, operations);
216 }
217 }
218 };
219}
220
221impl Display for TestError {
222 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
223 match self {
224 TestError::Mismatch {
225 missing,
226 extra,
227 expected,
228 } => {
229 if !missing.is_empty() {
230 write!(f, "Missing elements:\n{}\n", missing.join("\n"),)?;
231 }
232 if !extra.is_empty() {
233 write!(f, "Extra elements:\n{}\n", extra.join("\n"),)?;
234 }
235 write!(f, "Expected elements:\n{}", expected.join("\n"))?;
236 }
237 TestError::MoreThanOneElement { actual, expected } => {
238 write!(
239 f,
240 "Expected one of:\n{}\nBut got:\n{}",
241 expected.join("\n"),
242 actual.join("\n")
243 )?;
244 }
245 }
246
247 Ok(())
248 }
249}
250
251pub fn assert_elements_one_of<Graph>(
252 graph: &Graph,
253 actual: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
254 expected: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
255) -> Result<(), TestError>
256where
257 Graph: graph_api_lib::Graph,
258{
259 let actual: Vec<ElementId<Graph>> = actual.into_iter().map(Into::into).collect();
260 let expected: Vec<ElementId<Graph>> = expected.into_iter().map(Into::into).collect();
261
262 let actual_strings: Vec<String> = actual.iter().map(|e| graph.dbg(*e)).collect();
264 let expected_strings: Vec<String> = expected.iter().map(|e| graph.dbg(*e)).collect();
265
266 if actual.len() != 1 {
267 return Err(TestError::MoreThanOneElement {
268 expected: expected_strings,
269 actual: actual_strings,
270 });
271 }
272
273 Ok(())
274}
275
276pub fn assert_elements_eq<Graph>(
277 graph: &Graph,
278 actual: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
279 expected: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
280) -> Result<(), TestError>
281where
282 Graph: graph_api_lib::Graph,
283{
284 let actual = actual.into_iter().map(Into::into).collect::<HashSet<_>>();
285 let expected = expected.into_iter().map(Into::into).collect::<HashSet<_>>();
286 if actual != expected {
287 let missing: Vec<String> = expected
288 .difference(&actual)
289 .map(|e| graph.dbg(*e))
290 .collect();
291 let extra: Vec<String> = actual
292 .difference(&expected)
293 .map(|e| graph.dbg(*e))
294 .collect();
295
296 let expected: Vec<String> = expected.iter().map(|e| graph.dbg(*e)).collect();
297
298 return Err(TestError::Mismatch {
299 missing,
300 extra,
301 expected,
302 });
303 }
304 Ok(())
305}
306
307#[macro_export]
308macro_rules! assert_elements_eq {
309 ($graph:expr, $actual:expr, $expected:expr) => {
310 if let Err(e) = $crate::assert_elements_eq($graph, $actual, $expected) {
311 panic!("{}", e);
312 }
313 };
314}
315
316#[macro_export]
317macro_rules! assert_elements_one_of {
318 ($graph:expr, $actual:expr, $expected:expr) => {
319 if let Err(e) = $crate::assert_elements_one_of($graph, $actual, $expected) {
320 panic!("{}", e);
321 }
322 };
323}