use std::collections::HashSet;
use crate::core::ir::{EnumDef, FieldDef, TypeDef, TypeRef};
use crate::e2e::field_access::FieldResolver;
use super::ir_enum::{build_ir_enum_map, is_enum_path};
use super::types::IrEnumMap;
fn field(name: &str, ty: TypeRef) -> FieldDef {
FieldDef {
name: name.to_string(),
ty,
..FieldDef::default()
}
}
fn type_def(name: &str, fields: Vec<FieldDef>) -> TypeDef {
TypeDef {
name: name.to_string(),
fields,
..TypeDef::default()
}
}
fn enum_def(name: &str) -> EnumDef {
EnumDef {
name: name.to_string(),
..EnumDef::default()
}
}
fn ambiguous_kind_type_defs() -> Vec<TypeDef> {
vec![
type_def(
"DataNode",
vec![field("kind", TypeRef::Named("DataNodeKind".to_string()))],
),
type_def("PlainNode", vec![field("kind", TypeRef::String)]),
]
}
fn ambiguous_kind_enums() -> Vec<EnumDef> {
vec![enum_def("DataNodeKind")]
}
#[test]
fn a_field_whose_declared_type_is_a_real_enum_is_derived_as_enum() {
let map = build_ir_enum_map(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
let map = IrEnumMap {
root_type: Some("DataNode".to_string()),
..map
};
assert!(is_enum_path(&map, "kind"), "DataNode.kind is DataNodeKind, a real enum");
}
#[test]
fn a_field_with_the_same_name_but_a_string_type_on_a_different_owner_is_not_enum() {
let map = build_ir_enum_map(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
let map = IrEnumMap {
root_type: Some("PlainNode".to_string()),
..map
};
assert!(
!is_enum_path(&map, "kind"),
"PlainNode.kind is String — the bare name 'kind' must not decide this"
);
}
#[test]
fn an_option_wrapped_enum_field_is_derived_as_enum() {
let type_defs = vec![type_def(
"Response",
vec![field(
"status",
TypeRef::Optional(Box::new(TypeRef::Named("Status".to_string()))),
)],
)];
let enums = vec![enum_def("Status")];
let map = build_ir_enum_map(&type_defs, &enums);
let map = IrEnumMap {
root_type: Some("Response".to_string()),
..map
};
assert!(is_enum_path(&map, "status"), "Option<Status> must unwrap to the enum");
}
#[test]
fn a_vec_wrapped_element_field_reached_via_wildcard_traversal_is_derived_as_enum() {
let type_defs = vec![
type_def(
"Result",
vec![field(
"links",
TypeRef::Vec(Box::new(TypeRef::Named("Link".to_string()))),
)],
),
type_def("Link", vec![field("link_type", TypeRef::Named("LinkType".to_string()))]),
];
let enums = vec![enum_def("LinkType")];
let map = build_ir_enum_map(&type_defs, &enums);
let map = IrEnumMap {
root_type: Some("Result".to_string()),
..map
};
assert!(
is_enum_path(&map, "links[].link_type"),
"Vec<Link>.link_type must be reached through the wildcard array segment"
);
assert!(
!is_enum_path(&map, "link_type"),
"a bare leaf name must not resolve against the wrong owner type"
);
}
#[test]
fn a_nested_indexed_path_is_derived_as_enum() {
let type_defs = vec![
type_def(
"Response",
vec![field(
"choices",
TypeRef::Vec(Box::new(TypeRef::Named("Choice".to_string()))),
)],
),
type_def(
"Choice",
vec![field("finish_reason", TypeRef::Named("FinishReason".to_string()))],
),
];
let enums = vec![enum_def("FinishReason")];
let map = build_ir_enum_map(&type_defs, &enums);
let map = IrEnumMap {
root_type: Some("Response".to_string()),
..map
};
assert!(is_enum_path(&map, "choices[0].finish_reason"));
}
#[test]
fn a_missing_root_type_answers_false_rather_than_guessing() {
let map = build_ir_enum_map(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
assert!(!is_enum_path(&map, "kind"));
}
#[test]
fn a_path_through_an_unknown_field_answers_false() {
let map = build_ir_enum_map(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
let map = IrEnumMap {
root_type: Some("DataNode".to_string()),
..map
};
assert!(!is_enum_path(&map, "nonexistent_field"));
assert!(!is_enum_path(&map, "nonexistent_parent.kind"));
}
#[test]
fn field_resolver_is_enum_consults_the_ir_fallback_when_config_is_silent() {
let map = FieldResolver::ir_enum_fields(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
let resolver = FieldResolver::new(
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
)
.with_ir_enum_map(map, Some("DataNode".to_string()));
assert!(
resolver.is_enum("kind"),
"fields_enum was never configured; the IR alone must answer this"
);
}
#[test]
fn field_resolver_is_enum_does_not_misclassify_the_same_name_on_a_different_owner() {
let map = FieldResolver::ir_enum_fields(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
let resolver = FieldResolver::new(
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
)
.with_ir_enum_map(map, Some("PlainNode".to_string()));
assert!(!resolver.is_enum("kind"));
}
#[test]
fn an_explicit_fields_enum_entry_wins_even_when_the_ir_disagrees() {
let map = FieldResolver::ir_enum_fields(&ambiguous_kind_type_defs(), &ambiguous_kind_enums());
let resolver = FieldResolver::new(
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
)
.with_enum_fields(HashSet::from(["kind".to_string()]))
.with_ir_enum_map(map, Some("PlainNode".to_string()));
assert!(
resolver.is_enum("kind"),
"an explicit fields_enum entry must win over an IR disagreement"
);
}
#[test]
fn a_resolver_with_no_ir_enum_map_wired_in_behaves_exactly_as_before() {
let resolver = FieldResolver::new(
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
&Default::default(),
);
assert!(!resolver.is_enum("kind"));
let resolver = resolver.with_enum_fields(HashSet::from(["kind".to_string()]));
assert!(resolver.is_enum("kind"));
}