use super::rust_bindings::generate_bindings;
use crate::core::config::resolved::ResolvedCrateConfig;
use crate::core::config::{BridgeBinding, TraitBridgeConfig};
use crate::core::ir::{ApiSurface, MethodDef, ParamDef, TypeDef, TypeRef};
fn visitor_trait_def() -> TypeDef {
TypeDef {
name: "SampleVisitor".to_string(),
rust_path: "sample_core::SampleVisitor".to_string(),
is_trait: true,
methods: vec![MethodDef {
name: "visit_node".to_string(),
return_type: TypeRef::Named("VisitResult".to_string()),
params: vec![ParamDef {
name: "context".to_string(),
ty: TypeRef::Named("NodeContext".to_string()),
..Default::default()
}],
has_default_impl: true,
..Default::default()
}],
..Default::default()
}
}
fn visitor_bridge_config() -> TraitBridgeConfig {
TraitBridgeConfig {
trait_name: "SampleVisitor".to_string(),
type_alias: Some("SampleVisitorHandle".to_string()),
context_type: Some("NodeContext".to_string()),
result_type: Some("VisitResult".to_string()),
bind_via: BridgeBinding::FunctionParam,
..Default::default()
}
}
#[test]
fn visitor_interface_file_basename_matches_its_own_declared_class_name() {
let api = ApiSurface {
crate_name: "sample-core".to_string(),
version: "1.0.0".to_string(),
types: vec![visitor_trait_def()],
..Default::default()
};
let config = ResolvedCrateConfig {
name: "sample-core".to_string(),
trait_bridges: vec![visitor_bridge_config()],
..ResolvedCrateConfig::default()
};
let files = generate_bindings(&api, &config).expect("generate_bindings ok");
let interface_file = files
.iter()
.find(|f| f.path.extension().is_some_and(|ext| ext == "php") && f.content.contains("interface "))
.expect("a visitor bridge must emit one PHP interface file");
let declared_class = interface_file
.content
.lines()
.find_map(|line| line.strip_prefix("interface ").map(str::trim))
.expect("interface content must declare a class via `interface <Name>`");
let basename = interface_file
.path
.file_stem()
.and_then(|stem| stem.to_str())
.expect("interface file must have a UTF-8 basename");
assert_eq!(
basename,
declared_class,
"PSR-4 requires the file basename to match the declared class name -- file was {}, but \
its content declares `interface {declared_class}`",
interface_file.path.display()
);
assert_eq!(
declared_class, "SampleVisitorInterface",
"a visitor bridge's interface class must carry the `Interface` suffix, got: {declared_class}"
);
}