use super::snippet_regressions::compile_snippet;
use super::*;
use crate::core::ir::{MethodDef, ParamDef, TypeDef, TypeRef};
fn client_type_defs() -> Vec<TypeDef> {
vec![TypeDef {
name: "Client".into(),
is_opaque: true,
methods: vec![MethodDef {
name: "list_files".into(),
params: vec![
ParamDef {
name: "cursor".into(),
ty: TypeRef::Optional(Box::new(TypeRef::Named("Cursor".into()))),
optional: true,
..ParamDef::default()
},
ParamDef {
name: "note".into(),
ty: TypeRef::Optional(Box::new(TypeRef::String)),
optional: true,
..ParamDef::default()
},
],
return_type: TypeRef::Named("FileList".into()),
..MethodDef::default()
}],
..TypeDef::default()
}]
}
fn list_files_args() -> Vec<crate::e2e::config::ArgMapping> {
vec![
crate::e2e::config::ArgMapping {
name: "cursor".into(),
field: "input.cursor".into(),
arg_type: "string".into(),
optional: true,
owned: false,
element_type: None,
go_type: None,
vec_inner_is_ref: false,
trait_name: None,
},
crate::e2e::config::ArgMapping {
name: "note".into(),
field: "input.note".into(),
arg_type: "string".into(),
optional: true,
owned: false,
element_type: None,
go_type: None,
vec_inner_is_ref: false,
trait_name: None,
},
]
}
fn list_files_e2e_config() -> E2eConfig {
let mut e2e = E2eConfig::default();
e2e.call.function = "list_files".into();
e2e.call.args = list_files_args();
e2e.call.overrides.insert(
"c".into(),
crate::core::config::e2e::CallOverride {
client_factory: Some("create_client".into()),
header: Some("sample_ffi.h".into()),
..Default::default()
},
);
e2e
}
fn list_files_fixture() -> Fixture {
Fixture {
id: "list_files_defaults".into(),
description: "List files with no cursor or note".into(),
input: serde_json::json!({}),
..Fixture::default()
}
}
const HEADER: &str = concat!(
"#include <stdint.h>\n",
"typedef uint64_t SAMPLEAlefHandle;\n",
"SAMPLEAlefHandle sample_create_client(const char *api_key, const char *base_url, ",
"uint64_t timeout_ms, uint32_t max_retries, const char *user_agent);\n",
"void sample_default_client_free(SAMPLEAlefHandle client);\n",
"SAMPLEAlefHandle sample_default_client_list_files(SAMPLEAlefHandle client, ",
"SAMPLEAlefHandle cursor, const char *note);\n",
"void sample_file_list_free(SAMPLEAlefHandle result);\n",
);
#[test]
fn snippet_path_types_the_omitted_client_method_args() {
let fixture = list_files_fixture();
let e2e = list_files_e2e_config();
let config = ResolvedCrateConfig {
name: "sample".into(),
..ResolvedCrateConfig::default()
};
let type_defs = client_type_defs();
let rendered = render_c_snippet(&fixture, &e2e, &config, &type_defs, &[]).expect("snippet renders");
assert!(
rendered.contains("sample_default_client_list_files(client, 0, NULL)"),
"expected the handle-typed `cursor` to render `0` and the string-typed `note` to \
render `NULL`, got:\n{rendered}"
);
assert!(
!rendered.contains("sample_default_client_list_files(client, NULL, NULL)"),
"the handle-typed `cursor` must never render the pointer sentinel `NULL`:\n{rendered}"
);
compile_snippet(&rendered, "sample_ffi.h", HEADER);
}
#[test]
fn e2e_test_file_path_types_the_omitted_client_method_args() {
let fixture = list_files_fixture();
let e2e = list_files_e2e_config();
let config = ResolvedCrateConfig {
name: "sample".into(),
..ResolvedCrateConfig::default()
};
let type_defs = client_type_defs();
let field_resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
);
let ir = CallIr {
functions: &[],
type_defs: &type_defs,
};
let rendered = render_test_file(
"files",
&[&fixture],
"sample_ffi.h",
"sample",
"result",
&e2e,
"c",
&field_resolver,
&config,
&type_defs,
&[],
&[],
ir,
)
.expect("test file renders");
assert!(
rendered.contains("sample_default_client_list_files(client, 0, NULL)"),
"expected the handle-typed `cursor` to render `0` and the string-typed `note` to \
render `NULL`, got:\n{rendered}"
);
assert!(
!rendered.contains("sample_default_client_list_files(client, NULL, NULL)"),
"the handle-typed `cursor` must never render the pointer sentinel `NULL`:\n{rendered}"
);
}