use super::gen_enum;
use crate::backends::napi::gen_bindings::errors::gen_dts;
use crate::core::ir::{ApiSurface, EnumDef, EnumVariant, FieldDef, TypeRef};
fn sample_kind_enum() -> EnumDef {
EnumDef {
name: "SampleKind".to_string(),
rust_path: "test_core::SampleKind".to_string(),
variants: vec![
EnumVariant {
name: "Function".to_string(),
is_tuple: true,
fields: vec![FieldDef {
name: "_0".to_string(),
ty: TypeRef::String,
..Default::default()
}],
..Default::default()
},
EnumVariant {
name: "Idle".to_string(),
..Default::default()
},
],
..Default::default()
}
}
#[test]
fn runtime_struct_is_tagged_object_for_default_tagged_data_enum() {
let enum_def = sample_kind_enum();
let runtime = gen_enum(&enum_def, "Js", false, "test_core", None);
let expected = "\
#[derive(Clone)]
#[napi(object, js_name = \"SampleKind\")]
pub struct JsSampleKind {
#[napi(js_name = \"type\")]
pub type_tag: String,
pub function: Option<String>,
}
impl Default for JsSampleKind {
fn default() -> Self { Self { type_tag: \"Function\".to_string(), function: None } }
}";
assert_eq!(runtime, expected);
}
#[test]
fn dts_declaration_is_discriminated_union_for_default_tagged_data_enum() {
let enum_def = sample_kind_enum();
let api = ApiSurface {
enums: vec![enum_def],
..Default::default()
};
let dts = gen_dts(
&api,
"Js",
&Default::default(),
&[],
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
"",
None,
);
let start = dts
.find("export type SampleKind =")
.expect("gen_dts must declare SampleKind as a discriminated union type, not a plain enum");
let declaration = dts[start..].trim_end();
assert_eq!(
declaration,
"export type SampleKind =\n | { type: 'Function'; function: string }\n | { type: 'Idle' }"
);
}
#[test]
fn dts_and_runtime_agree_on_discriminant_and_payload_field_names() {
let enum_def = sample_kind_enum();
let runtime = gen_enum(&enum_def, "Js", false, "test_core", None);
let runtime_tag_line = runtime
.lines()
.find(|l| l.trim_start().starts_with("#[napi(js_name ="))
.expect("runtime struct must declare a js_name for its discriminant field");
assert_eq!(runtime_tag_line.trim(), "#[napi(js_name = \"type\")]");
let runtime_payload_line = runtime
.lines()
.find(|l| l.trim_start().starts_with("pub function:"))
.expect("runtime struct must declare the Function variant's payload field");
assert_eq!(runtime_payload_line.trim(), "pub function: Option<String>,");
let api = ApiSurface {
enums: vec![enum_def],
..Default::default()
};
let dts = gen_dts(
&api,
"Js",
&Default::default(),
&[],
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
"",
None,
);
let start = dts
.find("export type SampleKind =")
.expect("gen_dts must declare SampleKind as a discriminated union type, not a plain enum");
let function_member = dts[start..]
.lines()
.find(|l| l.trim_start().starts_with("| { type: 'Function';"))
.expect(".d.ts must declare the Function variant's member shape");
assert_eq!(function_member.trim(), "| { type: 'Function'; function: string }");
}