use super::bean_impl_gen;
use crate::handler::parse_handler_method;
use syn::{ImplItemFn, ItemImpl, parse_quote};
fn update_goldens() -> bool {
std::env::var("UPDATE_GOLDENS").is_ok_and(|v| v == "1")
}
fn baseline_path(name: &str) -> std::path::PathBuf {
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("src/baselines")
.join(name)
}
fn check(name: &str, produced: String) {
let path = baseline_path(name);
if update_goldens() {
let parent = path
.parent()
.unwrap_or_else(|| panic!("baseline {name} has no parent dir"));
std::fs::create_dir_all(parent).unwrap_or_else(|e| panic!("create baselines dir: {e}"));
std::fs::write(&path, &produced).unwrap_or_else(|e| panic!("write baseline {name}: {e}"));
} else {
let expected = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("read baseline {name}: {e} (capture: UPDATE_GOLDENS=1)"));
assert_eq!(expected, produced, "baseline {name} drifted");
}
}
#[test]
fn bean_impl_expansion_baseline_ok() {
let item: ItemImpl = parse_quote! {
impl OrderService {
#[handler]
pub async fn process(&self, body: String) -> Result<String, String> {
Ok(body)
}
#[handler]
pub async fn notify(&self) {}
}
};
match bean_impl_gen(item) {
Ok(tokens) => check("bean_impl_ok.txt", tokens.to_string()),
Err(e) => panic!("bean_impl_gen should succeed for valid input, got: {e}"),
}
}
#[test]
fn bean_impl_baseline_generic_reject() {
let item: ItemImpl = parse_quote! {
impl<T> GenericService<T> {
#[handler]
pub async fn process(&self, body: T) -> Result<T, String> {
Ok(body)
}
}
};
match bean_impl_gen(item) {
Ok(_) => panic!("bean_impl_gen should reject generic impl blocks"),
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("bean_impl does not support generic types"),
"unexpected diagnostic: {msg}"
);
check("bean_impl_generic_reject.txt", msg);
}
}
}
#[test]
fn bean_impl_baseline_no_handler_reject() {
let item: ItemImpl = parse_quote! {
impl MyService {
pub async fn process(&self) {}
}
};
match bean_impl_gen(item) {
Ok(_) => panic!("bean_impl_gen should reject impl blocks without handlers"),
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("No #[handler] methods found in impl block"),
"unexpected diagnostic: {msg}"
);
check("bean_impl_no_handler_reject.txt", msg);
}
}
}
#[test]
fn handler_baseline_self_reject() {
let method: ImplItemFn = parse_quote! {
#[handler]
pub fn handle(self) {}
};
match parse_handler_method(&method) {
Ok(_) => panic!("parse_handler_method should reject by-value self receivers"),
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("Handler methods must use &self, not self"),
"unexpected diagnostic: {msg}"
);
check("handler_self_reject.txt", msg);
}
}
}
#[test]
fn handler_baseline_nonasync_reject() {
let method: ImplItemFn = parse_quote! {
#[handler]
pub fn handle(&self) {}
};
match parse_handler_method(&method) {
Ok(_) => panic!("parse_handler_method should reject non-async handlers"),
Err(e) => check("handler_nonasync_reject.txt", e.to_string()),
}
}
#[test]
fn handler_baseline_dup_param_reject() {
let method: ImplItemFn = parse_quote! {
#[handler]
pub async fn h(&self, a: String, a: String) {}
};
match parse_handler_method(&method) {
Ok(_) => panic!("parse_handler_method should reject duplicate parameter names"),
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("Duplicate parameter name"),
"unexpected diagnostic: {msg}"
);
check("handler_dup_param_reject.txt", msg);
}
}
}