use crate::core::ir::TypeRef;
use crate::e2e::fixture::Fixture;
use crate::e2e::codegen::TestBackendEmission;
#[allow(unused_imports)]
pub fn emit_test_backend(
trait_bridge: &crate::core::config::TraitBridgeConfig,
methods: &[&crate::core::ir::MethodDef],
fixture: &Fixture,
enums: &[crate::core::ir::EnumDef],
) -> TestBackendEmission {
use crate::backends::dart::type_map::DartMapper;
use crate::codegen::defaults::language_defaults;
use crate::codegen::type_mapper::TypeMapper as _;
use heck::{ToLowerCamelCase, ToUpperCamelCase};
use std::fmt::Write as _;
use super::values::escape_dart;
let pascal_id = fixture.id.to_upper_camel_case();
let class_name = format!("TestStub{pascal_id}");
let trait_class = &trait_bridge.trait_name;
let plugin_name = fixture
.input
.get("name")
.and_then(|v| v.as_str())
.unwrap_or(&fixture.id)
.to_string();
let defaults = language_defaults("dart");
let mapper = DartMapper;
let mut needs_uint8list = false;
for method in methods {
for param in &method.params {
if param.ty == TypeRef::Bytes {
needs_uint8list = true;
}
}
if method.return_type == TypeRef::Bytes {
needs_uint8list = true;
}
}
let mut setup = String::new();
let _ = writeln!(setup, "class {class_name} extends {trait_class} {{");
if trait_bridge.super_trait.is_some() {
let escaped_name = escape_dart(&plugin_name);
let _ = writeln!(setup, " String get name => '{escaped_name}';");
}
for method in methods {
let method_name = method.name.to_lower_camel_case();
let params: Vec<String> = method
.params
.iter()
.map(|p| {
let param_type = map_dart_type_with_fallback(&mapper, &p.ty);
format!("{} {}", param_type, p.name.to_lower_camel_case())
})
.collect();
let params_str = params.join(", ");
let return_type = map_dart_type_with_fallback(&mapper, &method.return_type);
let default_val = emit_dart_default_for_type(defaults.as_ref(), &method.return_type, enums);
let _ = method.is_async;
let _ = writeln!(
setup,
" Future<{return_type}> {method_name}({params_str}) async => {default_val};"
);
}
let _ = writeln!(setup, "}}");
let create_fn = format!("create{}DartImpl", trait_bridge.trait_name);
let plugin_name = fixture
.input
.get("name")
.and_then(|v| v.as_str())
.unwrap_or(&fixture.id);
let instance_name = format!("_{class_name}_instance");
let factory_fn = format!("_create{class_name}Wrapper");
let _ = writeln!(setup, "final {instance_name} = {class_name}();");
let trait_name = &trait_bridge.trait_name;
let _ = writeln!(
setup,
"Future<{trait_name}DartImpl> {factory_fn}() async => await {create_fn}("
);
let escaped_plugin_name = escape_dart(plugin_name);
let _ = writeln!(setup, " pluginName: '{escaped_plugin_name}',");
let _ = writeln!(setup, " pluginVersion: '0.0.1',");
let emitted_methods: Vec<_> = methods.iter().filter(|m| !m.binding_excluded).collect();
for (i, method) in emitted_methods.iter().enumerate() {
let method_name = method.name.to_lower_camel_case();
let typed_params: Vec<String> = method
.params
.iter()
.map(|p| {
let ty = map_dart_type_with_fallback(&mapper, &p.ty);
format!("{} {}", ty, p.name.to_lower_camel_case())
})
.collect();
let typed_params_str = typed_params.join(", ");
let param_names: Vec<String> = method.params.iter().map(|p| p.name.to_lower_camel_case()).collect();
let arg_pass = param_names.join(", ");
let binding = if param_names.is_empty() {
format!("{method_name}: () => {instance_name}.{method_name}()")
} else {
format!("{method_name}: ({typed_params_str}) => {instance_name}.{method_name}({arg_pass})")
};
let comma = if i < emitted_methods.len() - 1 { "," } else { "" };
let _ = writeln!(setup, " {binding}{comma}");
}
let _ = writeln!(setup, ");");
let mut type_imports = Vec::new();
if needs_uint8list {
type_imports.push("dart:typed_data".to_string());
}
let factory_fn = format!("_create{class_name}Wrapper");
let arg_expr = format!("await {factory_fn}()");
TestBackendEmission {
setup_block: setup,
arg_expr,
type_imports,
teardown_block: String::new(),
}
}
pub(super) fn map_dart_type_with_fallback(
mapper: &crate::backends::dart::type_map::DartMapper,
ty: &crate::core::ir::TypeRef,
) -> String {
use crate::codegen::type_mapper::TypeMapper as _;
if let crate::core::ir::TypeRef::Named(name) = ty {
if name.contains("Internal") {
return format!("{name}Bridge");
}
}
mapper.map_type(ty).to_string()
}
pub(super) fn emit_dart_default_for_type(
defaults: &dyn crate::codegen::defaults::LanguageDefaults,
ty: &crate::core::ir::TypeRef,
enums: &[crate::core::ir::EnumDef],
) -> String {
let effective_ty = match ty {
TypeRef::Named(name) if name.contains("Internal") => TypeRef::Named(format!("{name}Bridge")),
_ => ty.clone(),
};
if let TypeRef::Named(name) = &effective_ty {
if let Some(enum_def) = enums.iter().find(|e| &e.name == name) {
if let Some(first_variant) = enum_def.variants.first() {
let variant_name = first_variant.name.to_lowercase();
return format!("{name}.{variant_name}");
}
}
return "throw UnimplementedError()".to_string();
}
if let TypeRef::Primitive(p) = &effective_ty {
use crate::core::ir::PrimitiveType;
match p {
PrimitiveType::Bool | PrimitiveType::F32 | PrimitiveType::F64 => {}
_ => return "1".to_string(),
}
}
defaults.emit_default(&effective_ty).to_string()
}