use super::{emit_test_backend, make_fixture, test_method};
#[test]
fn emit_test_backend_rust_generates_struct_and_arc_expr() {
use crate::core::config::TraitBridgeConfig;
use crate::core::ir::TypeRef;
let bridge = TraitBridgeConfig {
trait_name: "TestTrait".to_string(),
super_trait: Some("Plugin".to_string()),
register_fn: Some("register_test_trait".to_string()),
..Default::default()
};
let m1 = test_method("do_work", TypeRef::String, false, None);
let m2 = test_method(
"process_async",
TypeRef::Named("WorkResult".to_string()),
true,
Some("WorkError"),
);
let methods = [&m1, &m2];
let fixture = make_fixture("my_test_fixture", serde_json::json!({ "name": "my-test-backend" }));
let emission = emit_test_backend(&bridge, &methods, &fixture);
assert!(
emission.setup_block.contains("TestStubMyTestFixture"),
"setup_block should contain stub name, got: {}",
emission.setup_block
);
assert!(
emission.setup_block.contains("TestTrait"),
"setup_block should reference trait by name, got: {}",
emission.setup_block
);
assert!(
!emission.setup_block.contains("OcrBackend"),
"setup_block must not hardcode OcrBackend"
);
assert!(
!emission.setup_block.contains("DocumentExtractor"),
"setup_block must not hardcode DocumentExtractor"
);
assert!(
emission.setup_block.contains("fn name("),
"setup_block should emit name() when super_trait is set"
);
assert!(
emission.setup_block.contains("fn do_work("),
"required method do_work should be in setup_block"
);
assert!(
emission.setup_block.contains("fn process_async("),
"required async method process_async should be in setup_block"
);
assert!(
emission.arg_expr.contains("Arc::new"),
"arg_expr should use Arc::new, got: {}",
emission.arg_expr
);
assert!(
emission.arg_expr.contains("TestStubMyTestFixture"),
"arg_expr should reference stub struct, got: {}",
emission.arg_expr
);
}
#[test]
fn emit_test_backend_rust_skips_default_impl_methods() {
use crate::core::config::TraitBridgeConfig;
use crate::core::ir::TypeRef;
let bridge = TraitBridgeConfig {
trait_name: "TestTrait".to_string(),
..Default::default()
};
let required = test_method("required_method", TypeRef::String, false, None);
let mut optional = test_method("optional_method", TypeRef::String, false, None);
optional.has_default_impl = true;
let methods = [&required, &optional];
let fixture = make_fixture("skip_defaults_fixture", serde_json::json!({}));
let emission = emit_test_backend(&bridge, &methods, &fixture);
assert!(
emission.setup_block.contains("fn required_method("),
"required method should be emitted"
);
assert!(
!emission.setup_block.contains("fn optional_method("),
"method with default impl should be skipped"
);
}
#[test]
fn emit_test_backend_rust_name_extracted_from_input() {
use crate::core::config::TraitBridgeConfig;
let bridge = TraitBridgeConfig {
trait_name: "TestTrait".to_string(),
super_trait: Some("Plugin".to_string()),
..Default::default()
};
let fixture = make_fixture(
"name_extraction_fixture",
serde_json::json!({ "backend": { "name": "extracted-name" } }),
);
let emission = emit_test_backend(&bridge, &[], &fixture);
assert!(
emission.arg_expr.contains("extracted-name"),
"arg_expr should contain the name from input.backend.name, got: {}",
emission.arg_expr
);
}
#[test]
fn emit_test_backend_rust_pins_error_type_to_the_method_signature() {
use crate::core::config::TraitBridgeConfig;
use crate::core::ir::TypeRef;
let bridge = TraitBridgeConfig {
trait_name: "TestTrait".to_string(),
super_trait: Some("Plugin".to_string()),
..Default::default()
};
let method = test_method(
"embed",
TypeRef::Vec(Box::new(TypeRef::String)),
true,
Some("SampleCrateError"),
);
let methods = [&method];
let fixture = make_fixture("error_type_fixture", serde_json::json!({ "name": "backend" }));
let emission = emit_test_backend(&bridge, &methods, &fixture);
assert!(
emission
.setup_block
.contains("async fn embed(&self) -> Result<Vec<String>, SampleCrateError>"),
"stub signature must use the method's declared error type, got: {}",
emission.setup_block
);
assert!(
emission.type_imports.contains(&"SampleCrateError".to_string()),
"the declared error type must be imported, got: {:?}",
emission.type_imports
);
assert_eq!(
emission
.type_imports
.iter()
.filter(|import| import.ends_with("Error"))
.collect::<Vec<_>>(),
vec![&"SampleCrateError".to_string()],
"no error type other than the declared one may be imported, got: {:?}",
emission.type_imports
);
}
#[test]
fn emit_test_backend_rust_renders_alias_result_through_the_crate_module() {
use crate::core::config::TraitBridgeConfig;
use crate::core::ir::TypeRef;
let bridge = TraitBridgeConfig {
trait_name: "TestTrait".to_string(),
super_trait: Some("sample_core::plugins::Plugin".to_string()),
..Default::default()
};
let method = test_method("validate", TypeRef::Unit, true, Some("anyhow::Error"));
let methods = [&method];
let fixture = make_fixture("alias_result_fixture", serde_json::json!({ "name": "backend" }));
let emission = emit_test_backend(&bridge, &methods, &fixture);
assert!(
emission
.setup_block
.contains("async fn validate(&self) -> sample_core::Result<()>"),
"single-arg Result alias must render through the crate module, got: {}",
emission.setup_block
);
assert!(
!emission.type_imports.iter().any(|import| import.contains("Error")),
"the alias sentinel must not become an error-type import, got: {:?}",
emission.type_imports
);
}