use super::*;
use crate::core::config::e2e::{ArgMapping, CallOverride};
fn clear_backends_config() -> ResolvedCrateConfig {
ResolvedCrateConfig {
name: "sample".into(),
trait_bridges: vec![crate::core::config::TraitBridgeConfig {
trait_name: "SampleBackend".into(),
clear_fn: Some("clear_sample_backends".into()),
unregister_fn: Some("unregister_sample_backend".into()),
..Default::default()
}],
..ResolvedCrateConfig::default()
}
}
fn clear_call(function: &str) -> CallConfig {
CallConfig {
function: function.into(),
returns_result: false,
returns_void: true,
..CallConfig::default()
}
}
fn clear_fixture() -> Fixture {
Fixture {
id: "clear_sample_backends".into(),
description: "Clear registered sample backends".into(),
call: Some("clear_sample_backends".into()),
..Fixture::default()
}
}
#[test]
fn configured_base_function_does_not_shadow_the_derived_clear_symbol() {
let mut e2e = E2eConfig::default();
e2e.calls
.insert("clear_sample_backends".into(), clear_call("clear_sample_backends"));
let info = resolve_fixture_call_info(&clear_fixture(), &e2e, &clear_backends_config(), "c", CallIr::default());
assert_eq!(info.function_name, "clear_sample_backend");
}
#[test]
fn configured_base_function_does_not_shadow_the_clear_out_error_out_param() {
let mut e2e = E2eConfig::default();
e2e.calls
.insert("clear_sample_backends".into(), clear_call("clear_sample_backends"));
let info = resolve_fixture_call_info(&clear_fixture(), &e2e, &clear_backends_config(), "c", CallIr::default());
assert_eq!(info.extra_args, vec!["NULL".to_string()]);
}
#[test]
fn rendered_snippet_calls_the_derived_clear_symbol_with_its_out_param() {
let mut e2e = E2eConfig::default();
e2e.calls
.insert("clear_sample_backends".into(), clear_call("clear_sample_backends"));
let rendered =
render_c_snippet(&clear_fixture(), &e2e, &clear_backends_config(), &[], &[]).expect("C snippet renders");
assert!(rendered.contains("sample_clear_sample_backend(NULL)"), "{rendered}");
assert!(!rendered.contains("sample_clear_sample_backends("), "{rendered}");
}
#[test]
fn configured_base_function_does_not_shadow_the_unregister_out_error_out_param() {
let fixture = Fixture {
id: "unregister_sample_backend".into(),
description: "Unregister a sample backend".into(),
call: Some("unregister_sample_backend".into()),
input: serde_json::json!({ "name": "nonexistent-backend" }),
..Fixture::default()
};
let mut e2e = E2eConfig::default();
e2e.calls.insert(
"unregister_sample_backend".into(),
CallConfig {
function: "unregister_sample_backend".into(),
returns_result: false,
returns_void: true,
args: vec![ArgMapping {
name: "name".into(),
field: "input.name".into(),
arg_type: "string".into(),
optional: false,
owned: false,
element_type: None,
go_type: None,
vec_inner_is_ref: false,
trait_name: None,
}],
..CallConfig::default()
},
);
let rendered = render_c_snippet(&fixture, &e2e, &clear_backends_config(), &[], &[]).expect("C snippet renders");
assert!(
rendered.contains("sample_unregister_sample_backend(\"nonexistent-backend\", NULL)"),
"{rendered}"
);
}
#[test]
fn an_explicit_c_function_override_still_outranks_the_derived_symbol() {
let mut e2e = E2eConfig::default();
let mut call = clear_call("clear_sample_backends");
call.overrides.insert(
"c".into(),
CallOverride {
function: Some("sample_drop_every_backend".into()),
..CallOverride::default()
},
);
e2e.calls.insert("clear_sample_backends".into(), call);
let info = resolve_fixture_call_info(&clear_fixture(), &e2e, &clear_backends_config(), "c", CallIr::default());
assert_eq!(info.function_name, "sample_drop_every_backend");
}
#[test]
fn a_fixture_level_skip_does_not_block_the_derivation() {
let mut e2e = E2eConfig::default();
e2e.calls
.insert("clear_sample_backends".into(), clear_call("clear_sample_backends"));
let mut fixture = clear_fixture();
fixture.skip = Some(crate::e2e::fixture::SkipDirective {
languages: vec!["c".into()],
reason: Some("the register-shaped call sharing this trait cannot cross the C ABI".into()),
});
let info = resolve_fixture_call_info(&fixture, &e2e, &clear_backends_config(), "c", CallIr::default());
assert_eq!(info.function_name, "clear_sample_backend");
assert_eq!(info.extra_args, vec!["NULL".to_string()]);
}
#[test]
fn a_call_level_skip_still_blocks_the_derivation() {
let mut e2e = E2eConfig::default();
let mut call = clear_call("clear_sample_backends");
call.skip_languages = vec!["c".into()];
e2e.calls.insert("clear_sample_backends".into(), call);
let info = resolve_fixture_call_info(&clear_fixture(), &e2e, &clear_backends_config(), "c", CallIr::default());
assert_eq!(
info.function_name, "clear_sample_backends",
"a call-level skip_languages must leave the naive config text uncorrected -- this fixture \
should never have reached a C generator at all, so its output is not this test's concern"
);
}
#[test]
fn rendered_snippet_calls_the_derived_symbol_despite_a_fixture_level_skip() {
let mut e2e = E2eConfig::default();
e2e.calls
.insert("clear_sample_backends".into(), clear_call("clear_sample_backends"));
let mut fixture = clear_fixture();
fixture.skip = Some(crate::e2e::fixture::SkipDirective {
languages: vec!["c".into()],
reason: Some("the register-shaped call sharing this trait cannot cross the C ABI".into()),
});
let rendered = render_c_snippet(&fixture, &e2e, &clear_backends_config(), &[], &[]).expect("C snippet renders");
assert!(rendered.contains("sample_clear_sample_backend(NULL)"), "{rendered}");
assert!(!rendered.contains("sample_clear_sample_backends("), "{rendered}");
}