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/src/lib.rs') 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/src/lib.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'sylt_macro/src/lib.rs') 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/src/lib.rs') 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/src/lib.rs') 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