Introduce a `gpui::test` macro

Antonio Scandurra created

Change summary

Cargo.lock             |  9 +++++++++
Cargo.toml             |  2 +-
gpui/Cargo.toml        |  1 +
gpui/src/lib.rs        |  1 +
gpui_macros/Cargo.toml | 11 +++++++++++
gpui_macros/src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++++
6 files changed, 62 insertions(+), 1 deletion(-)

Detailed changes

Cargo.lock 🔗

@@ -1180,6 +1180,7 @@ dependencies = [
  "etagere",
  "font-kit",
  "foreign-types",
+ "gpui_macros",
  "log",
  "metal",
  "num_cpus",
@@ -1205,6 +1206,14 @@ dependencies = [
  "usvg",
 ]
 
+[[package]]
+name = "gpui_macros"
+version = "0.1.0"
+dependencies = [
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "hashbrown"
 version = "0.9.1"

Cargo.toml 🔗

@@ -1,5 +1,5 @@
 [workspace]
-members = ["zed", "gpui", "fsevent", "scoped_pool"]
+members = ["zed", "gpui", "gpui_macros", "fsevent", "scoped_pool"]
 
 [patch.crates-io]
 async-task = {git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e"}

gpui/Cargo.toml 🔗

@@ -8,6 +8,7 @@ version = "0.1.0"
 async-task = "4.0.3"
 ctor = "0.1"
 etagere = "0.2"
+gpui_macros = {path = "../gpui_macros"}
 log = "0.4"
 num_cpus = "1.13"
 ordered-float = "2.1.1"

gpui/src/lib.rs 🔗

@@ -24,6 +24,7 @@ pub mod color;
 pub mod json;
 pub mod keymap;
 mod platform;
+pub use gpui_macros::test;
 pub use platform::{Event, PathPromptOptions};
 pub use presenter::{
     AfterLayoutContext, Axis, DebugContext, EventContext, LayoutContext, PaintContext,

gpui_macros/Cargo.toml 🔗

@@ -0,0 +1,11 @@
+[package]
+name = "gpui_macros"
+version = "0.1.0"
+edition = "2018"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+syn = "1.0"
+quote = "1.0"

gpui_macros/src/lib.rs 🔗

@@ -0,0 +1,39 @@
+use std::mem;
+
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, ItemFn};
+
+#[proc_macro_attribute]
+pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
+    assert!(args.is_empty());
+
+    let mut inner_fn = parse_macro_input!(function as ItemFn);
+    let inner_fn_name = format_ident!("_{}", inner_fn.sig.ident);
+    let outer_fn_name = mem::replace(&mut inner_fn.sig.ident, inner_fn_name.clone());
+    let outer_fn = if inner_fn.sig.asyncness.is_some() {
+        quote! {
+            #[test]
+            fn #outer_fn_name() {
+                #inner_fn
+
+                gpui::App::test_async((), move |ctx| async {
+                    #inner_fn_name(ctx).await;
+                });
+            }
+        }
+    } else {
+        quote! {
+            #[test]
+            fn #outer_fn_name() {
+                #inner_fn
+
+                gpui::App::test((), |ctx| {
+                    #inner_fn_name(ctx);
+                });
+            }
+        }
+    };
+
+    TokenStream::from(outer_fn)
+}