From 1fe1f3bdb42908c11a8f21df1b25ffabbdb01d6a Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Thu, 20 Jul 2023 17:25:12 +0000 Subject: [PATCH 1/2] Generate invariant-enforcing tests in stubgen adapters. --- trustfall/src/lib.rs | 4 +-- trustfall_stubgen/README.md | 1 + trustfall_stubgen/src/adapter_creator.rs | 5 +++ trustfall_stubgen/src/root.rs | 35 ++++++++++++++++++- trustfall_stubgen/src/tests.rs | 3 +- .../hackernews/adapter/adapter_impl.rs | 5 +++ .../hackernews/adapter/mod.rs | 3 ++ .../hackernews/adapter/tests.rs | 10 ++++++ .../hackernews/adapter/vertex.rs | 1 + 9 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/tests.rs diff --git a/trustfall/src/lib.rs b/trustfall/src/lib.rs index 154e7d1d..22b518d9 100644 --- a/trustfall/src/lib.rs +++ b/trustfall/src/lib.rs @@ -47,8 +47,8 @@ pub mod provider { // Helpers for common operations when building adapters. pub use trustfall_core::interpreter::helpers::{ - resolve_coercion_using_schema, resolve_coercion_with, resolve_neighbors_with, - resolve_property_with, resolve_typename, + check_adapter_invariants, resolve_coercion_using_schema, resolve_coercion_with, + resolve_neighbors_with, resolve_property_with, resolve_typename }; pub use trustfall_core::{accessor_property, field_property}; diff --git a/trustfall_stubgen/README.md b/trustfall_stubgen/README.md index ccd31baa..0a458220 100644 --- a/trustfall_stubgen/README.md +++ b/trustfall_stubgen/README.md @@ -22,6 +22,7 @@ The generated Trustfall adapter stub has the following structure: | adapter/entrypoints.rs | contains the entry points where all queries must start | | adapter/properties.rs | contains the property implementations | | adapter/edges.rs | contains the edge implementations | +| adapter/tests.rs | contains test code | See an example of [a generated adapter stub](https://github.com/obi1kenobi/trustfall/tree/main/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter) diff --git a/trustfall_stubgen/src/adapter_creator.rs b/trustfall_stubgen/src/adapter_creator.rs index 36137b84..81c6145f 100644 --- a/trustfall_stubgen/src/adapter_creator.rs +++ b/trustfall_stubgen/src/adapter_creator.rs @@ -23,6 +23,7 @@ pub(super) fn make_adapter_file( }; let adapter_defn = quote! { + #[non_exhaustive] #[derive(Debug)] pub struct Adapter {} }; @@ -45,6 +46,10 @@ pub(super) fn make_adapter_file( pub fn schema() -> &'static Schema { SCHEMA.get_or_init(|| Schema::parse(Self::SCHEMA_TEXT).expect("not a valid schema")) } + + pub fn new() -> Self { + Self {} + } } }; diff --git a/trustfall_stubgen/src/root.rs b/trustfall_stubgen/src/root.rs index f0b824f0..1f7d81bc 100644 --- a/trustfall_stubgen/src/root.rs +++ b/trustfall_stubgen/src/root.rs @@ -10,6 +10,8 @@ use quote::quote; use regex::Regex; use trustfall::{Schema, SchemaAdapter, TryIntoStruct}; +use crate::util::parse_import; + use super::{ adapter_creator::make_adapter_file, edges_creator::make_edges_file, entrypoints_creator::make_entrypoints_file, properties_creator::make_properties_file, @@ -25,6 +27,7 @@ use super::{ /// - adapter/entrypoints.rs contains the entry points where all queries must start /// - adapter/properties.rs contains the property implementations /// - adapter/edges.rs contains the edge implementations +/// - adapter/tests.rs contains test code /// /// # Example /// ```no_run @@ -62,13 +65,13 @@ pub fn generate_rust_stub(schema: &str, target: &Path) -> anyhow::Result<()> { &mut stub.properties, ); make_edges_file(&querying_schema, schema_adapter.clone(), &mut stub.edges); - make_adapter_file( &querying_schema, schema_adapter.clone(), &mut stub.adapter_impl, entrypoint_match_arms, ); + make_tests_file(&mut stub.tests); stub.write_to_directory(target) } @@ -266,6 +269,7 @@ struct AdapterStub<'a> { entrypoints: RustFile, properties: RustFile, edges: RustFile, + tests: RustFile, } impl<'a> AdapterStub<'a> { @@ -279,6 +283,10 @@ impl<'a> AdapterStub<'a> { mod properties; mod edges; }); + mod_.top_level_items.push(quote! { + #[cfg(test)] + mod tests; + }); mod_.top_level_items.push(quote! { pub use adapter_impl::Adapter; pub use vertex::Vertex; @@ -292,6 +300,7 @@ impl<'a> AdapterStub<'a> { entrypoints: Default::default(), properties: Default::default(), edges: Default::default(), + tests: Default::default(), } } @@ -328,10 +337,33 @@ impl<'a> AdapterStub<'a> { self.edges.write_to_file(path_buf.as_path())?; path_buf.pop(); + path_buf.push("tests.rs"); + self.tests.write_to_file(path_buf.as_path())?; + path_buf.pop(); + Ok(()) } } +fn make_tests_file(tests_file: &mut RustFile) { + tests_file.external_imports.insert(parse_import( + "trustfall::provider::check_adapter_invariants", + )); + + tests_file + .internal_imports + .insert(parse_import("super::Adapter")); + + tests_file.top_level_items.push(quote! { + #[test] + fn adapter_satisfies_trustfall_invariants() { + let adapter = Adapter::new(); + let schema = Adapter::schema(); + check_adapter_invariants(schema, adapter); + } + }); +} + fn make_vertex_file( querying_schema: &Schema, adapter: Arc>, @@ -368,6 +400,7 @@ fn make_vertex_file( } let vertex = quote! { + #[non_exhaustive] #[derive(Debug, Clone, trustfall::provider::TrustfallEnumVertex)] pub enum Vertex { #variants diff --git a/trustfall_stubgen/src/tests.rs b/trustfall_stubgen/src/tests.rs index 74590d09..93e11f9c 100644 --- a/trustfall_stubgen/src/tests.rs +++ b/trustfall_stubgen/src/tests.rs @@ -77,12 +77,11 @@ fn get_relevant_files_from_dir(path: &Path) -> BTreeMap { let mut dir_glob = path.to_path_buf(); dir_glob.push("**"); dir_glob.push("*"); - dbg!(&dir_glob); glob::glob(dir_glob.to_str().expect("failed to convert path to &str")) .expect("failed to list dir") .filter_map(|res| { - let pathbuf = dbg!(res.expect("failed to check file")); + let pathbuf = res.expect("failed to check file"); if !pathbuf.is_file() { return None; } diff --git a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/adapter_impl.rs b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/adapter_impl.rs index f0e8cd00..6cb48002 100644 --- a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/adapter_impl.rs +++ b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/adapter_impl.rs @@ -6,6 +6,7 @@ use super::vertex::Vertex; static SCHEMA: OnceLock = OnceLock::new(); +#[non_exhaustive] #[derive(Debug)] pub struct Adapter {} @@ -18,6 +19,10 @@ impl Adapter { Schema::parse(Self::SCHEMA_TEXT).expect("not a valid schema") }) } + + pub fn new() -> Self { + Self {} + } } impl<'a> trustfall::provider::Adapter<'a> for Adapter { diff --git a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/mod.rs b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/mod.rs index aaade94a..ba4cb201 100644 --- a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/mod.rs +++ b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/mod.rs @@ -4,5 +4,8 @@ mod entrypoints; mod properties; mod edges; +#[cfg(test)] +mod tests; + pub use adapter_impl::Adapter; pub use vertex::Vertex; diff --git a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/tests.rs b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/tests.rs new file mode 100644 index 00000000..f1b35ecb --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/tests.rs @@ -0,0 +1,10 @@ +use trustfall::provider::check_adapter_invariants; + +use super::Adapter; + +#[test] +fn adapter_satisfies_trustfall_invariants() { + let adapter = Adapter::new(); + let schema = Adapter::schema(); + check_adapter_invariants(schema, adapter); +} diff --git a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/vertex.rs b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/vertex.rs index 0127a45c..e8c5ee69 100644 --- a/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/vertex.rs +++ b/trustfall_stubgen/test_data/expected_outputs/hackernews/adapter/vertex.rs @@ -1,3 +1,4 @@ +#[non_exhaustive] #[derive(Debug, Clone, trustfall::provider::TrustfallEnumVertex)] pub enum Vertex { Comment(()), From a81d7263043dbcfe4cdb347a2a769ee87c180a4e Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Thu, 20 Jul 2023 18:00:56 +0000 Subject: [PATCH 2/2] cargo fmt. --- trustfall/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trustfall/src/lib.rs b/trustfall/src/lib.rs index 22b518d9..8ede8edd 100644 --- a/trustfall/src/lib.rs +++ b/trustfall/src/lib.rs @@ -48,7 +48,7 @@ pub mod provider { // Helpers for common operations when building adapters. pub use trustfall_core::interpreter::helpers::{ check_adapter_invariants, resolve_coercion_using_schema, resolve_coercion_with, - resolve_neighbors_with, resolve_property_with, resolve_typename + resolve_neighbors_with, resolve_property_with, resolve_typename, }; pub use trustfall_core::{accessor_property, field_property};