use super::test_backend::resolve_test_backend_emission;
use crate::core::config::{ResolvedCrateConfig, TraitBridgeConfig};
use crate::core::ir::{MethodDef, TypeDef, TypeRef};
use crate::e2e::fixture::Fixture;
fn fixture(id: &str) -> Fixture {
serde_json::from_value(serde_json::json!({
"id": id,
"description": "test",
"input": null,
}))
.expect("fixture")
}
fn method(name: &str, ret: TypeRef) -> MethodDef {
MethodDef {
name: name.to_string(),
return_type: ret,
..MethodDef::default()
}
}
fn own_trait_type_def(trait_name: &str, methods: Vec<MethodDef>) -> TypeDef {
TypeDef {
name: trait_name.to_string(),
is_trait: true,
methods,
..TypeDef::default()
}
}
fn plugin_bridge(trait_name: &str) -> TraitBridgeConfig {
TraitBridgeConfig {
trait_name: trait_name.to_string(),
super_trait: Some("sample_crate::plugins::Plugin".to_string()),
register_fn: Some(format!("register_{trait_name}")),
..TraitBridgeConfig::default()
}
}
#[test]
fn synthesizes_all_four_plugin_methods_when_the_super_trait_lookup_finds_nothing() {
let trait_bridge = plugin_bridge("SampleBackend");
let own_method = method("do_work", TypeRef::Primitive(crate::core::ir::PrimitiveType::Bool));
let type_defs = vec![own_trait_type_def("SampleBackend", vec![own_method])];
let config = ResolvedCrateConfig {
trait_bridges: vec![trait_bridge.clone()],
..ResolvedCrateConfig::default()
};
let fixture = fixture("synth_all_four");
let emission = resolve_test_backend_emission(
&fixture,
"SampleBackend",
&trait_bridge,
&config,
&type_defs,
&[],
"pkg",
);
assert!(
emission.setup_block.contains("Name() string"),
"missing Name() string:\n{}",
emission.setup_block
);
assert!(
emission.setup_block.contains("Version() string"),
"missing Version() string:\n{}",
emission.setup_block
);
assert!(
emission.setup_block.contains("Initialize() error"),
"missing Initialize() error:\n{}",
emission.setup_block
);
assert!(
emission.setup_block.contains("Shutdown() error"),
"missing Shutdown() error:\n{}",
emission.setup_block
);
assert!(
emission.setup_block.contains("DoWork()"),
"own trait method dropped:\n{}",
emission.setup_block
);
}
#[test]
fn synthesized_name_method_returns_the_fixture_id() {
let trait_bridge = plugin_bridge("SampleBackend");
let type_defs = vec![own_trait_type_def("SampleBackend", vec![])];
let config = ResolvedCrateConfig {
trait_bridges: vec![trait_bridge.clone()],
..ResolvedCrateConfig::default()
};
let fixture = fixture("name_returns_fixture_id");
let emission = resolve_test_backend_emission(
&fixture,
"SampleBackend",
&trait_bridge,
&config,
&type_defs,
&[],
"pkg",
);
assert!(
emission
.setup_block
.contains("Name() string { return \"name_returns_fixture_id\" }"),
"Name() must return the fixture id, got:\n{}",
emission.setup_block
);
}
#[test]
fn no_super_trait_configured_synthesizes_nothing() {
let mut trait_bridge = plugin_bridge("SampleBackend");
trait_bridge.super_trait = None;
let type_defs = vec![own_trait_type_def(
"SampleBackend",
vec![method(
"do_work",
TypeRef::Primitive(crate::core::ir::PrimitiveType::Bool),
)],
)];
let config = ResolvedCrateConfig {
trait_bridges: vec![trait_bridge.clone()],
..ResolvedCrateConfig::default()
};
let fixture = fixture("no_super_trait");
let emission = resolve_test_backend_emission(
&fixture,
"SampleBackend",
&trait_bridge,
&config,
&type_defs,
&[],
"pkg",
);
assert!(!emission.setup_block.contains("Initialize"), "{}", emission.setup_block);
assert!(!emission.setup_block.contains("Shutdown"), "{}", emission.setup_block);
assert!(
!emission.setup_block.contains("func (testStub_no_super_trait) Name"),
"{}",
emission.setup_block
);
}
#[test]
fn does_not_duplicate_a_method_the_trait_already_declares() {
let trait_bridge = plugin_bridge("SampleBackend");
let type_defs = vec![own_trait_type_def(
"SampleBackend",
vec![method(
"version",
TypeRef::Primitive(crate::core::ir::PrimitiveType::I32),
)],
)];
let config = ResolvedCrateConfig {
trait_bridges: vec![trait_bridge.clone()],
..ResolvedCrateConfig::default()
};
let fixture = fixture("no_duplicate_version");
let emission = resolve_test_backend_emission(
&fixture,
"SampleBackend",
&trait_bridge,
&config,
&type_defs,
&[],
"pkg",
);
let version_count = emission.setup_block.matches("Version(").count();
assert_eq!(
version_count, 1,
"Version() must appear exactly once:\n{}",
emission.setup_block
);
assert!(
emission.setup_block.contains("Version() int32"),
"the trait's own Version() signature must win, got:\n{}",
emission.setup_block
);
}
#[test]
fn uses_the_real_super_trait_methods_when_the_lookup_succeeds() {
let trait_bridge = plugin_bridge("SampleBackend");
let plugin_type = TypeDef {
name: "Plugin".to_string(),
rust_path: "sample_crate::plugins::Plugin".to_string(),
is_trait: true,
methods: vec![
method("name", TypeRef::String),
method("version", TypeRef::String),
method("initialize", TypeRef::Unit),
method("shutdown", TypeRef::Unit),
],
..TypeDef::default()
};
let type_defs = vec![own_trait_type_def("SampleBackend", vec![]), plugin_type];
let config = ResolvedCrateConfig {
trait_bridges: vec![trait_bridge.clone()],
..ResolvedCrateConfig::default()
};
let fixture = fixture("lookup_succeeds");
let emission = resolve_test_backend_emission(
&fixture,
"SampleBackend",
&trait_bridge,
&config,
&type_defs,
&[],
"pkg",
);
for needle in ["Name(", "Version(", "Initialize(", "Shutdown("] {
let count = emission.setup_block.matches(needle).count();
assert_eq!(count, 1, "{needle} must appear exactly once:\n{}", emission.setup_block);
}
}