rsonpath_test_codegen/
lib.rs1#![warn(
3 explicit_outlives_requirements,
4 semicolon_in_expressions_from_macros,
5 unreachable_pub,
6 unused_import_braces,
7 unused_lifetimes
8)]
9#![warn(
11 clippy::allow_attributes_without_reason,
12 clippy::cast_lossless,
13 clippy::cloned_instead_of_copied,
14 clippy::empty_drop,
15 clippy::empty_line_after_outer_attr,
16 clippy::equatable_if_let,
17 clippy::expl_impl_clone_on_copy,
18 clippy::explicit_deref_methods,
19 clippy::explicit_into_iter_loop,
20 clippy::explicit_iter_loop,
21 clippy::fallible_impl_from,
22 clippy::flat_map_option,
23 clippy::if_then_some_else_none,
24 clippy::inconsistent_struct_constructor,
25 clippy::large_digit_groups,
26 clippy::let_underscore_must_use,
27 clippy::manual_ok_or,
28 clippy::map_err_ignore,
29 clippy::map_unwrap_or,
30 clippy::match_same_arms,
31 clippy::match_wildcard_for_single_variants,
32 clippy::mod_module_files,
33 clippy::must_use_candidate,
34 clippy::needless_continue,
35 clippy::needless_for_each,
36 clippy::needless_pass_by_value,
37 clippy::ptr_as_ptr,
38 clippy::redundant_closure_for_method_calls,
39 clippy::ref_binding_to_reference,
40 clippy::ref_option_ref,
41 clippy::rest_pat_in_fully_bound_structs,
42 clippy::undocumented_unsafe_blocks,
43 clippy::unneeded_field_pattern,
44 clippy::unseparated_literal_suffix,
45 clippy::unreadable_literal,
46 clippy::unused_self,
47 clippy::use_self
48)]
49
50use crate::files::Files;
51use proc_macro2::TokenStream;
52use quote::quote;
53use std::{
54 fmt::Display,
55 io,
56 path::{Path, PathBuf},
57 time::{Duration, Instant},
58};
59
60mod compression;
61mod files;
62mod gen;
63mod model;
64
65#[derive(Clone)]
67pub(crate) struct DiscoveredDocument {
68 pub(crate) name: String,
70 pub(crate) relative_path: PathBuf,
72 pub(crate) document: model::Document,
74}
75
76pub fn generate_tests<P1, P2>(toml_directory_path: P1, output_json_directory_path: P2) -> Result<TokenStream, io::Error>
80where
81 P1: AsRef<Path>,
82 P2: AsRef<Path>,
83{
84 println!("discovery...");
85
86 let discovery_start = Instant::now();
87 let mut files = Files::new(output_json_directory_path, toml_directory_path)?;
88
89 println!("generating compressed variants...");
90
91 compression::generate_compressed_documents(&mut files)?;
92
93 let stats = files.stats();
94 let discovery_elapsed = FormatDuration(discovery_start.elapsed());
95
96 println!(
97 "prepared {} documents with a total of {} queries; finished in {}",
98 stats.number_of_documents(),
99 stats.number_of_queries(),
100 discovery_elapsed
101 );
102
103 println!("generating tests...");
104
105 let imports = gen::generate_imports();
106 let sources = gen::generate_test_fns(&mut files).into_iter();
107
108 println!("writing files...");
109 files.flush()?;
110
111 Ok(quote! {
112 #imports
113
114 #(#sources)*
115 })
116}
117
118struct FormatDuration(Duration);
120
121impl Display for FormatDuration {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 write!(f, "{:.2}s", self.0.as_secs_f32())
124 }
125}