From ba2a7b3290102e3573cc7b2727026f4efe8a1d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 17:43:16 +0100 Subject: macro that generates tests from files --- sylt_macro/src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) (limited to 'sylt_macro') diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 3b8b37c..0f1a584 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -1,5 +1,7 @@ +use std::path::{Path, PathBuf}; + use proc_macro::TokenStream; -use quote::quote; +use quote::{format_ident, quote}; use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input}; struct ExternBlock { @@ -137,7 +139,6 @@ impl Parse for Links { } } - #[proc_macro] pub fn link(tokens: TokenStream) -> TokenStream { let links: Links = parse_macro_input!(tokens); @@ -159,3 +160,44 @@ pub fn link(tokens: TokenStream) -> TokenStream { }; TokenStream::from(tokens) } + +fn find_test_paths(directory: &Path) -> Vec { + let mut tests = Vec::new(); + + for entry in std::fs::read_dir(directory).unwrap() { + let path = entry.unwrap().path(); + let file_name = path.file_name().unwrap().to_str().unwrap(); + + if file_name.starts_with("_") { + continue; + } + + if path.is_dir() { + tests.append(&mut find_test_paths(&path)); + } else { + assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); + tests.push(path); + } + } + + tests +} + +#[proc_macro] +pub fn find_tests(tokens: TokenStream) -> TokenStream { + assert!(tokens.is_empty()); + + let tests: Vec<_> = find_test_paths(Path::new("progs/")).iter().map(|path| { + let path = path.to_str().unwrap(); + let test_name = format_ident!("{}", path.replace("/", "_").replace(".sy", "")); + quote! { + test_file!(#test_name, #path); + } + }).collect(); + + let tokens = quote! { + #(#tests)* + }; + + TokenStream::from(tokens) +} -- cgit v1.2.1 From e1e7337239066677dd6bc82b826e861cf6710836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 18:14:05 +0100 Subject: expand test-files in modules --- sylt_macro/Cargo.toml | 5 +++-- sylt_macro/src/lib.rs | 38 +++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 21 deletions(-) (limited to 'sylt_macro') diff --git a/sylt_macro/Cargo.toml b/sylt_macro/Cargo.toml index 9ac045e..6d3c75f 100644 --- a/sylt_macro/Cargo.toml +++ b/sylt_macro/Cargo.toml @@ -10,5 +10,6 @@ proc-macro = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn = { version = "1.0", features=["full"] } -quote = "1.0" +syn = { version = "1", features=["full"] } +proc-macro2 = "1" +quote = "1" diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 0f1a584..c306592 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use proc_macro::TokenStream; use quote::{format_ident, quote}; @@ -161,8 +161,8 @@ pub fn link(tokens: TokenStream) -> TokenStream { TokenStream::from(tokens) } -fn find_test_paths(directory: &Path) -> Vec { - let mut tests = Vec::new(); +fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { + let mut tests = quote! {}; for entry in std::fs::read_dir(directory).unwrap() { let path = entry.unwrap().path(); @@ -173,31 +173,31 @@ fn find_test_paths(directory: &Path) -> Vec { } if path.is_dir() { - tests.append(&mut find_test_paths(&path)); + tests.extend(find_test_paths(&path)); } else { assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); - tests.push(path); + + let path = path.to_str().unwrap(); + let test_name = format_ident!("file_{}", file_name.replace(".sy", "")); + let tokens = quote! { + test_file!(#test_name, #path); + }; + tests.extend(tokens); } } - tests + let directory = directory.file_name().unwrap().to_str().unwrap().replace("/", ""); + let directory = format_ident!("{}", directory); + quote! { + mod #directory { + #tests + } + } } #[proc_macro] pub fn find_tests(tokens: TokenStream) -> TokenStream { assert!(tokens.is_empty()); - let tests: Vec<_> = find_test_paths(Path::new("progs/")).iter().map(|path| { - let path = path.to_str().unwrap(); - let test_name = format_ident!("{}", path.replace("/", "_").replace(".sy", "")); - quote! { - test_file!(#test_name, #path); - } - }).collect(); - - let tokens = quote! { - #(#tests)* - }; - - TokenStream::from(tokens) + TokenStream::from(find_test_paths(Path::new("progs/"))) } -- cgit v1.2.1 From 9d0a930d811b825b39ee16614e645b6934130cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 18:37:23 +0100 Subject: parse wanted errors from test files --- sylt_macro/src/lib.rs | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) (limited to 'sylt_macro') diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index c306592..96f7112 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -1,6 +1,5 @@ use std::path::Path; -use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input}; @@ -45,7 +44,7 @@ impl Parse for ExternFunction { } #[proc_macro] -pub fn extern_function(tokens: TokenStream) -> TokenStream { +pub fn extern_function(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { let parsed: ExternFunction = parse_macro_input!(tokens); let function = parsed.function; @@ -91,7 +90,7 @@ pub fn extern_function(tokens: TokenStream) -> TokenStream { } } }; - TokenStream::from(tokens) + proc_macro::TokenStream::from(tokens) } struct LinkRename { @@ -140,7 +139,7 @@ impl Parse for Links { } #[proc_macro] -pub fn link(tokens: TokenStream) -> TokenStream { +pub fn link(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { let links: Links = parse_macro_input!(tokens); let links: Vec<_> = links.links.iter().map(|link| { @@ -158,7 +157,16 @@ pub fn link(tokens: TokenStream) -> TokenStream { let tokens = quote! { vec![ #(#links),* ] }; - TokenStream::from(tokens) + proc_macro::TokenStream::from(tokens) +} + +fn parse_test(contents: String) -> Option { + for line in contents.split("\n") { + if line.starts_with("// errors: ") { + return Some(line.strip_prefix("// errors: ").unwrap().to_string()); + } + } + None } fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { @@ -177,11 +185,20 @@ fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { } else { assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); - let path = path.to_str().unwrap(); + let path_string = path.to_str().unwrap(); let test_name = format_ident!("file_{}", file_name.replace(".sy", "")); - let tokens = quote! { - test_file!(#test_name, #path); + + let tokens = if let Some(wanted_err) = parse_test(std::fs::read_to_string(path.clone()).unwrap()) { + let wanted_err: proc_macro2::TokenStream = wanted_err.parse().unwrap(); + quote! { + test_file!(#test_name, #path_string, #wanted_err); + } + } else { + quote! { + test_file!(#test_name, #path_string); + } }; + tests.extend(tokens); } } @@ -196,8 +213,9 @@ fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { } #[proc_macro] -pub fn find_tests(tokens: TokenStream) -> TokenStream { +pub fn find_tests(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { assert!(tokens.is_empty()); - TokenStream::from(find_test_paths(Path::new("progs/"))) + let tokens = find_test_paths(Path::new("progs/")); + proc_macro::TokenStream::from(tokens) } -- cgit v1.2.1 From b1fab16befb78232d7a913f58beef639c5891e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:47:00 +0100 Subject: set no_print in tests --- sylt_macro/src/lib.rs | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) (limited to 'sylt_macro') diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 96f7112..95b79c6 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -160,13 +160,41 @@ pub fn link(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { proc_macro::TokenStream::from(tokens) } -fn parse_test(contents: String) -> Option { +struct TestSettings { + errors: Option, + print: bool, +} + +impl Default for TestSettings { + fn default() -> Self { + Self { + errors: None, + print: true, + } + } +} + +fn parse_test_settings(contents: String) -> TestSettings { + let mut settings = TestSettings::default(); + for line in contents.split("\n") { if line.starts_with("// errors: ") { - return Some(line.strip_prefix("// errors: ").unwrap().to_string()); + settings.errors = Some(line.strip_prefix("// errors: ").unwrap().to_string()); + } else if line.starts_with("// flags: ") { + for flag in line.split(" ").skip(2) { + match flag { + "no_print" => { + settings.print = false; + } + _ => { + panic!("Unknown test flag '{}'", flag); + } + } + } } } - None + + settings } fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { @@ -188,14 +216,16 @@ fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { let path_string = path.to_str().unwrap(); let test_name = format_ident!("file_{}", file_name.replace(".sy", "")); - let tokens = if let Some(wanted_err) = parse_test(std::fs::read_to_string(path.clone()).unwrap()) { - let wanted_err: proc_macro2::TokenStream = wanted_err.parse().unwrap(); + let settings = parse_test_settings(std::fs::read_to_string(path.clone()).unwrap()); + let print = settings.print; + let tokens = if let Some(wanted_errs) = settings.errors { + let wanted_errs: proc_macro2::TokenStream = wanted_errs.parse().unwrap(); quote! { - test_file!(#test_name, #path_string, #wanted_err); + test_file!(#test_name, #path_string, #print, #wanted_errs); } } else { quote! { - test_file!(#test_name, #path_string); + test_file!(#test_name, #path_string, #print); } }; -- cgit v1.2.1 From 4ddcde3072c79a96544f6fa10f26070a54632d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 14:16:37 +0100 Subject: cargo maintenance --- sylt_macro/Cargo.lock | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 sylt_macro/Cargo.lock (limited to 'sylt_macro') diff --git a/sylt_macro/Cargo.lock b/sylt_macro/Cargo.lock new file mode 100644 index 0000000..137e02a --- /dev/null +++ b/sylt_macro/Cargo.lock @@ -0,0 +1,45 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sylt_macro" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -- cgit v1.2.1