Skip to content

Commit

Permalink
refactor: simplify macro testing infrastructure (#1040)
Browse files Browse the repository at this point in the history
  • Loading branch information
crowlKats authored Jan 9, 2025
1 parent b6308e5 commit fb8ce24
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 201 deletions.
20 changes: 11 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 1 addition & 6 deletions ops/compile_test_runner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,16 @@ authors.workspace = true
edition.workspace = true
license.workspace = true
publish = false
readme = "README.md"
repository.workspace = true
description = "Compile-test runner for deno_ops"

[lib]
path = "lib.rs"

[dev-dependencies]
bytes.workspace = true
deno_core.workspace = true
deno_error.workspace = true
deno_ops.workspace = true
pretty_assertions.workspace = true
prettyplease = "0.2.9"
rustversion = "1.0"
serde.workspace = true
syn.workspace = true
testing_macros = "0.2.11"
trybuild = "1.0"
31 changes: 31 additions & 0 deletions ops/compile_test_runner/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2018-2025 the Deno authors. MIT license.

#[macro_export]
macro_rules! prelude {
() => {
#[allow(unused_imports)]
use deno_ops::op2;
#[allow(unused_imports)]
use deno_ops::WebIDL;

pub fn main() {}
};
}

#[cfg(test)]
mod compile_tests {
#[test]
fn op2() {
let t = trybuild::TestCases::new();
t.pass("../op2/test_cases/**/*.rs");
t.pass("../op2/test_cases/compiler_pass/*.rs");
t.compile_fail("../op2/test_cases_fail/**/*.rs");
}

#[test]
fn webidl() {
let t = trybuild::TestCases::new();
t.pass("../webidl/test_cases/*.rs");
t.compile_fail("../webidl/test_cases_fail/*.rs");
}
}
70 changes: 0 additions & 70 deletions ops/compile_test_runner/src/lib.rs

This file was deleted.

54 changes: 54 additions & 0 deletions ops/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,57 @@ pub fn webidl(item: TokenStream) -> TokenStream {
Err(err) => err.into_compile_error().into(),
}
}

#[cfg(test)]
mod infra {
use std::path::PathBuf;
use syn::File;

pub fn run_macro_expansion_test<F, I>(input: PathBuf, expander: F)
where
F: FnOnce(File) -> I,
I: Iterator<Item = proc_macro2::TokenStream>,
{
let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();

let source =
std::fs::read_to_string(&input).expect("Failed to read test file");

const PRELUDE: &str = r"// Copyright 2018-2025 the Deno authors. MIT license.
#![deny(warnings)]
deno_ops_compile_test_runner::prelude!();";

if !source.starts_with(PRELUDE) {
panic!("Source does not start with expected prelude:]n{PRELUDE}");
}

let file =
syn::parse_str::<File>(&source).expect("Failed to parse Rust file");

let expected_out = expander(file)
.map(|tokens| {
println!("======== Raw tokens ========:\n{}", tokens.clone());
let tree = syn::parse2(tokens).unwrap();
let actual = prettyplease::unparse(&tree);
println!("======== Generated ========:\n{}", actual);
actual
})
.collect::<Vec<String>>()
.join("\n");

if update_expected {
std::fs::write(input.with_extension("out"), expected_out)
.expect("Failed to write expectation file");
} else {
let expected = std::fs::read_to_string(input.with_extension("out"))
.expect("Failed to read expectation file");

pretty_assertions::assert_eq!(
expected,
expected_out,
"Failed to match expectation. Use UPDATE_EXPECTED=1."
);
}
}
}
79 changes: 22 additions & 57 deletions ops/op2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,6 @@ mod tests {
use pretty_assertions::assert_eq;
use quote::ToTokens;
use std::path::PathBuf;
use syn::File;
use syn::Item;

fn to_attr_input(op2_attr: syn::Attribute) -> TokenStream {
Expand All @@ -385,6 +384,11 @@ mod tests {
.map(|(idx, attr)| (idx, attr.to_owned()))
}

fn expand_op2(op2_attr: syn::Attribute, item: impl ToTokens) -> TokenStream {
op2(to_attr_input(op2_attr), item.to_token_stream())
.expect("Failed to generate op")
}

#[testing_macros::fixture("op2/test_cases/sync/*.rs")]
fn test_proc_macro_sync(input: PathBuf) {
test_proc_macro_output(input)
Expand All @@ -395,67 +399,28 @@ mod tests {
test_proc_macro_output(input)
}

fn expand_op2(op2_attr: syn::Attribute, item: impl ToTokens) -> String {
let tokens = op2(to_attr_input(op2_attr), item.to_token_stream())
.expect("Failed to generate op");
println!("======== Raw tokens ========:\n{}", tokens.clone());
let tree = syn::parse2(tokens).unwrap();
let actual = prettyplease::unparse(&tree);
println!("======== Generated ========:\n{}", actual);
actual
}

fn test_proc_macro_output(input: PathBuf) {
let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();

let source =
std::fs::read_to_string(&input).expect("Failed to read test file");

const PRELUDE: &str = r"// Copyright 2018-2025 the Deno authors. MIT license.
#![deny(warnings)]
deno_ops_compile_test_runner::prelude!();";

if !source.starts_with(PRELUDE) {
panic!("Source does not start with expected prelude:]n{PRELUDE}");
}

let file =
syn::parse_str::<File>(&source).expect("Failed to parse Rust file");
let mut expected_out = vec![];
for item in file.items {
match item {
Item::Fn(mut func) => {
if let Some((idx, op2_attr)) = find_op2_attr(&func.attrs) {
func.attrs.remove(idx);
let actual = expand_op2(op2_attr, func);
expected_out.push(actual);
crate::infra::run_macro_expansion_test(input, |file| {
file.items.into_iter().filter_map(|item| {
match item {
Item::Fn(mut func) => {
if let Some((idx, op2_attr)) = find_op2_attr(&func.attrs) {
func.attrs.remove(idx);
return Some(expand_op2(op2_attr, func));
}
}
}
Item::Impl(mut imp) => {
if let Some((idx, op2_attr)) = find_op2_attr(&imp.attrs) {
imp.attrs.remove(idx);
let actual = expand_op2(op2_attr, imp);
expected_out.push(actual);
Item::Impl(mut imp) => {
if let Some((idx, op2_attr)) = find_op2_attr(&imp.attrs) {
imp.attrs.remove(idx);
return Some(expand_op2(op2_attr, imp));
}
}
_ => {}
}
_ => {}
}
}

let expected_out = expected_out.join("\n");

if update_expected {
std::fs::write(input.with_extension("out"), expected_out)
.expect("Failed to write expectation file");
} else {
let expected = std::fs::read_to_string(input.with_extension("out"))
.expect("Failed to read expectation file");
assert_eq!(
expected, expected_out,
"Failed to match expectation. Use UPDATE_EXPECTED=1."
);
}
None
})
})
}

fn parse_md(md: &str, mut f: impl FnMut(&str, Vec<&str>)) {
Expand Down
Loading

0 comments on commit fb8ce24

Please sign in to comment.