use super::{adapter_flattened_field, gen_adapter_wrapper};
use crate::core::config::{AdapterConfig, AdapterParam, AdapterPattern};
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
fn streaming_adapter(params: Vec<AdapterParam>, request_type: Option<&str>) -> AdapterConfig {
AdapterConfig {
name: "crawl_stream".to_string(),
pattern: AdapterPattern::Streaming,
core_path: "sample::CrawlEngine::crawl_stream".to_string(),
params,
returns: None,
error_type: None,
owner_type: Some("CrawlEngineHandle".to_string()),
item_type: Some("sample::CrawlEvent".to_string()),
gil_release: false,
trait_name: None,
trait_method: None,
detect_async: false,
request_type: request_type.map(str::to_string),
skip_languages: Vec::new(),
}
}
fn adapter_param(name: &str, ty: &str) -> AdapterParam {
AdapterParam {
name: name.to_string(),
ty: ty.to_string(),
optional: false,
}
}
fn dto(name: &str, fields: Vec<FieldDef>) -> TypeDef {
TypeDef {
name: name.to_string(),
fields,
..TypeDef::default()
}
}
fn field(name: &str, ty: TypeRef) -> FieldDef {
FieldDef {
name: name.to_string(),
ty,
..FieldDef::default()
}
}
fn signature_line(rendered: &str) -> &str {
rendered
.lines()
.find(|line| line.trim_start().starts_with("func "))
.expect("gen_adapter_wrapper always emits a `func` line")
}
fn call_line(rendered: &str) -> &str {
rendered
.lines()
.find(|line| line.trim_start().starts_with("return "))
.expect("gen_adapter_wrapper always emits a `return` line")
}
fn request_construction_line(rendered: &str) -> Option<&str> {
rendered.lines().find(|line| line.trim_start().starts_with("req :="))
}
#[test]
fn flattens_the_single_configured_params_first_field() {
let adapter = streaming_adapter(
vec![adapter_param("request", "CrawlRequest")],
Some("sample::CrawlRequest"),
);
let types = vec![dto("CrawlRequest", vec![field("url", TypeRef::String)])];
let flattened = adapter_flattened_field(&adapter, &types);
assert_eq!(flattened.map(|f| f.name.as_str()), Some("url"));
assert_eq!(flattened.map(|f| &f.ty), Some(&TypeRef::String));
}
#[test]
fn does_not_flatten_two_configured_params() {
let adapter = streaming_adapter(
vec![adapter_param("url", "String"), adapter_param("depth", "u32")],
Some("sample::CrawlRequest"),
);
let types = vec![dto("CrawlRequest", vec![field("url", TypeRef::String)])];
assert!(adapter_flattened_field(&adapter, &types).is_none());
}
#[test]
fn does_not_flatten_a_fieldless_request_type() {
let adapter = streaming_adapter(
vec![adapter_param("request", "CrawlRequest")],
Some("sample::CrawlRequest"),
);
let types = vec![dto("CrawlRequest", Vec::new())];
assert!(adapter_flattened_field(&adapter, &types).is_none());
}
#[test]
fn does_not_flatten_when_the_param_type_is_absent_from_the_ir() {
let adapter = streaming_adapter(
vec![adapter_param("request", "CrawlRequest")],
Some("sample::CrawlRequest"),
);
assert!(adapter_flattened_field(&adapter, &[]).is_none());
}
#[test]
fn does_not_flatten_without_a_configured_request_type() {
let adapter = streaming_adapter(vec![adapter_param("request", "CrawlRequest")], None);
let types = vec![dto("CrawlRequest", vec![field("url", TypeRef::String)])];
assert!(adapter_flattened_field(&adapter, &types).is_none());
}
#[test]
fn single_param_adapter_decomposes_into_a_scalar_go_parameter() {
let adapter = streaming_adapter(
vec![adapter_param("request", "CrawlRequest")],
Some("sample::CrawlRequest"),
);
let types = vec![dto("CrawlRequest", vec![field("url", TypeRef::String)])];
let rendered = gen_adapter_wrapper(&adapter, "pkg", &types);
assert_eq!(
signature_line(&rendered),
"func CrawlStream(engine *CrawlEngineHandle, URL string) (<-chan CrawlEvent, error) {"
);
assert_eq!(
request_construction_line(&rendered),
Some("\treq := &CrawlRequest{URL: URL}")
);
assert_eq!(call_line(&rendered), "\treturn engine.CrawlStream(*req)");
}
#[test]
fn two_param_adapter_exposes_each_configured_param_directly() {
let adapter = streaming_adapter(
vec![adapter_param("url", "String"), adapter_param("depth", "u32")],
Some("sample::CrawlRequest"),
);
let types = vec![dto("CrawlRequest", vec![field("url", TypeRef::String)])];
let rendered = gen_adapter_wrapper(&adapter, "pkg", &types);
assert_eq!(
signature_line(&rendered),
"func CrawlStream(engine *CrawlEngineHandle, url string, depth u32) (<-chan CrawlEvent, error) {"
);
assert_eq!(request_construction_line(&rendered), None);
assert_eq!(call_line(&rendered), "\treturn engine.CrawlStream(url, depth)");
}
#[test]
fn fieldless_request_type_falls_back_to_the_configured_param() {
let adapter = streaming_adapter(
vec![adapter_param("request", "CrawlRequest")],
Some("sample::CrawlRequest"),
);
let types = vec![dto("CrawlRequest", Vec::new())];
let rendered = gen_adapter_wrapper(&adapter, "pkg", &types);
assert_eq!(
signature_line(&rendered),
"func CrawlStream(engine *CrawlEngineHandle, request CrawlRequest) (<-chan CrawlEvent, error) {"
);
assert_eq!(request_construction_line(&rendered), None);
assert_eq!(call_line(&rendered), "\treturn engine.CrawlStream(request)");
}