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, filter_test_vertices_filter, $crate::steps::filter::test_vertices_filter}
151 $crate::general_test!{$setup, filter_test_edges_filter, $crate::steps::filter::test_edges_filter}
152 $crate::general_test!{$setup, vertices_test_vertices_collect, $crate::steps::collect::test_vertices_collect}
153 $crate::general_test!{$setup, vertices_test_edges_collect, $crate::steps::collect::test_edges_collect}
154 $crate::general_test!{$setup, edges_test_out_edges, $crate::steps::edges::test_out_edges}
155 $crate::general_test!{$setup, edges_test_out_edges_limit, $crate::steps::edges::test_out_edges_limit}
156 $crate::general_test!{$setup, edges_test_in_edges, $crate::steps::edges::test_in_edges}
157 $crate::general_test!{$setup, edges_test_in_edges_limit, $crate::steps::edges::test_in_edges_limit}
158 $crate::general_test!{$setup, edges_test_all_edges, $crate::steps::edges::test_all_edges}
159 $crate::general_test!{$setup, edges_test_all_edges_limit, $crate::steps::edges::test_all_edges_limit}
160 $crate::general_test!{$setup, edges_test_out_edges_filtered, $crate::steps::edges::test_out_edges_filtered}
161 $crate::general_test!{$setup, edges_test_out_edges_filtered_limit, $crate::steps::edges::test_out_edges_filtered_limit}
162 $crate::general_test!{$setup, edges_test_in_edges_filtered, $crate::steps::edges::test_in_edges_filtered}
163 $crate::general_test!{$setup, edges_test_in_edges_filtered_limit, $crate::steps::edges::test_in_edges_filtered_limit}
164 $crate::general_test!{$setup, edges_test_all_edges_filtered, $crate::steps::edges::test_all_edges_filtered}
165 $crate::general_test!{$setup, edges_test_all_edges_filtered_limit, $crate::steps::edges::test_all_edges_filtered_limit}
166 $crate::general_test!{$setup, context_test_vertices_context, $crate::steps::context::test_vertices_context}
167 $crate::general_test!{$setup, vertices_test_take, $crate::steps::vertices::test_take}
168 $crate::general_test!{$setup, vertices_test_head, $crate::steps::vertices::test_head}
169 $crate::general_test!{$setup, vertices_test_tail, $crate::steps::vertices::test_tail}
170 $crate::general_test!{$setup, mutate_context_vertex, $crate::steps::mutate_context::test_vertex_mutate_context}
171 $crate::general_test!{$setup, mutate_context_edge, $crate::steps::mutate_context::test_edge_mutate_context}
172 $crate::general_test!{$setup, mutation_test_mutation, $crate::steps::mutation::test_mutation}
173 $crate::general_test!{$setup, mutation_test_edge_mutation, $crate::steps::mutation::test_edge_mutation}
174 $crate::general_test!{$setup, count_test_vertices_count, $crate::steps::count::test_vertices_count}
175 $crate::general_test!{$setup, count_test_edges_count, $crate::steps::count::test_edges_count}
176 $crate::general_test!{$setup, take_test_vertices_take, $crate::steps::take::test_vertices_take}
177 $crate::general_test!{$setup, take_test_edges_take, $crate::steps::take::test_edges_take}
178 $crate::general_test!{$setup, first_test_vertices_first, $crate::steps::first::test_vertices_first}
179 $crate::general_test!{$setup, first_test_edges_first, $crate::steps::first::test_edges_first}
180 $crate::general_test!{$setup, fold_test_vertices_fold, $crate::steps::fold::test_vertices_fold}
181 $crate::general_test!{$setup, fold_test_edges_fold, $crate::steps::fold::test_edges_fold}
182 $crate::general_test!{$setup, reduce_test_vertices_reduce, $crate::steps::reduce::test_vertices_reduce}
183 $crate::general_test!{$setup, reduce_test_edges_reduce, $crate::steps::reduce::test_edges_reduce}
184 $crate::general_test!{$setup, detour_test_vertices_detour, $crate::steps::detour::test_vertices_detour}
185 $crate::general_test!{$setup, filter_derive_test_vertices_filter, $crate::steps::filter_derive::test_vertices_filter}
186 $crate::general_test!{$setup, filter_derive_test_edges_filter, $crate::steps::filter_derive::test_edges_filter}
187 $crate::general_test!{$setup, probe_test_vertices_probe, $crate::steps::probe::test_vertices_probe}
188 $crate::general_test!{$setup, probe_test_edges_probe, $crate::steps::probe::test_edges_probe}
189 $crate::general_test!{$setup, control_flow_test_vertices_control_flow, $crate::steps::control_flow::test_vertices_control_flow}
190 $crate::general_test!{$setup, control_flow_test_edges_control_flow, $crate::steps::control_flow::test_edges_control_flow}
191 $crate::general_test!{$setup, index_edge_label_test_index, $crate::index::edge_label::test_index}
192 $crate::general_test!{$setup, index_edge_label_test_index_limit, $crate::index::edge_label::test_index_limit}
193 $crate::general_test!{$setup, index_vertex_label_test_index, $crate::index::vertex_label::test_index}
194 $crate::general_test!{$setup, index_vertex_label_test_index_limit, $crate::index::vertex_label::test_index_limit}
195 $crate::general_test!{$setup, index_vertex_hash_test_index, $crate::index::vertex_hash::test_index}
196 $crate::general_test!{$setup, index_vertex_hash_test_index_remove, $crate::index::vertex_hash::test_index_remove}
197 $crate::general_test!{$setup, index_vertex_hash_test_index_update, $crate::index::vertex_hash::test_index_update}
198 $crate::general_test!{$setup, index_vertex_full_text_test_index, $crate::index::vertex_full_text::test_index}
199 $crate::general_test!{$setup, index_vertex_full_text_test_index_remove, $crate::index::vertex_full_text::test_index_remove}
200 $crate::general_test!{$setup, index_vertex_full_text_test_index_update, $crate::index::vertex_full_text::test_index_update}
201 $crate::general_test!{$setup, index_vertex_range_test_index, $crate::index::vertex_range::test_index}
202 $crate::general_test!{$setup, index_vertex_range_test_index_remove, $crate::index::vertex_range::test_index_remove}
203 $crate::general_test!{$setup, index_vertex_range_test_index_update, $crate::index::vertex_range::test_index_update}
204
205 $crate::proptest! {
206 #[test]
207 fn fuzz_test(operations in $crate::collection::vec($crate::fuzz::arb_graph_operation(), 0..100)) {
208 $crate::fuzz::test_fuzz($setup, operations);
209 }
210 }
211 };
212}
213
214impl Display for TestError {
215 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
216 match self {
217 TestError::Mismatch {
218 missing,
219 extra,
220 expected,
221 } => {
222 if !missing.is_empty() {
223 write!(f, "Missing elements:\n{}\n", missing.join("\n"),)?;
224 }
225 if !extra.is_empty() {
226 write!(f, "Extra elements:\n{}\n", extra.join("\n"),)?;
227 }
228 write!(f, "Expected elements:\n{}", expected.join("\n"))?;
229 }
230 TestError::MoreThanOneElement { actual, expected } => {
231 write!(
232 f,
233 "Expected one of:\n{}\nBut got:\n{}",
234 expected.join("\n"),
235 actual.join("\n")
236 )?;
237 }
238 }
239
240 Ok(())
241 }
242}
243
244pub fn assert_elements_one_of<Graph>(
245 graph: &Graph,
246 actual: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
247 expected: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
248) -> Result<(), TestError>
249where
250 Graph: graph_api_lib::Graph,
251{
252 let actual: Vec<ElementId<Graph>> = actual.into_iter().map(Into::into).collect();
253 let expected: Vec<ElementId<Graph>> = expected.into_iter().map(Into::into).collect();
254
255 let actual_strings: Vec<String> = actual.iter().map(|e| graph.dbg(*e)).collect();
257 let expected_strings: Vec<String> = expected.iter().map(|e| graph.dbg(*e)).collect();
258
259 if actual.len() != 1 {
260 return Err(TestError::MoreThanOneElement {
261 expected: expected_strings,
262 actual: actual_strings,
263 });
264 }
265
266 Ok(())
267}
268
269pub fn assert_elements_eq<Graph>(
270 graph: &Graph,
271 actual: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
272 expected: impl IntoIterator<Item = impl Into<ElementId<Graph>>>,
273) -> Result<(), TestError>
274where
275 Graph: graph_api_lib::Graph,
276{
277 let actual = actual.into_iter().map(Into::into).collect::<HashSet<_>>();
278 let expected = expected.into_iter().map(Into::into).collect::<HashSet<_>>();
279 if actual != expected {
280 let missing: Vec<String> = expected
281 .difference(&actual)
282 .map(|e| graph.dbg(*e))
283 .collect();
284 let extra: Vec<String> = actual
285 .difference(&expected)
286 .map(|e| graph.dbg(*e))
287 .collect();
288
289 let expected: Vec<String> = expected.iter().map(|e| graph.dbg(*e)).collect();
290
291 return Err(TestError::Mismatch {
292 missing,
293 extra,
294 expected,
295 });
296 }
297 Ok(())
298}
299
300#[macro_export]
301macro_rules! assert_elements_eq {
302 ($graph:expr, $actual:expr, $expected:expr) => {
303 if let Err(e) = $crate::assert_elements_eq($graph, $actual, $expected) {
304 panic!("{}", e);
305 }
306 };
307}
308
309#[macro_export]
310macro_rules! assert_elements_one_of {
311 ($graph:expr, $actual:expr, $expected:expr) => {
312 if let Err(e) = $crate::assert_elements_one_of($graph, $actual, $expected) {
313 panic!("{}", e);
314 }
315 };
316}