use super::FieldResolver;
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
use std::collections::{HashMap, HashSet};
fn set(entries: &[&str]) -> HashSet<String> {
entries.iter().map(|s| (*s).to_string()).collect()
}
fn document_type_defs() -> Vec<TypeDef> {
vec![TypeDef {
name: "Document".to_string(),
fields: vec![
FieldDef {
name: "chunks".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("Chunk".to_string()))),
optional: true,
..FieldDef::default()
},
FieldDef {
name: "title".to_string(),
ty: TypeRef::String,
optional: true,
..FieldDef::default()
},
],
..TypeDef::default()
}]
}
fn resolver_anchored_at_document() -> FieldResolver {
let type_defs = document_type_defs();
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
)
.with_ir_collection_map(
FieldResolver::ir_collection_fields(&type_defs),
Some("Document".to_string()),
)
.with_ir_result_fields(
FieldResolver::ir_result_field_facts(&type_defs, "rust"),
Some("Document".to_string()),
)
.with_ir_fields(reachable, excluded, optional)
}
#[test]
fn is_array_true_from_ir_when_fields_array_config_is_silent() {
let resolver = resolver_anchored_at_document();
assert!(
resolver.is_array("chunks"),
"is_array must be true when only the IR knows chunks is a Vec, got: false"
);
}
#[test]
fn is_array_stays_false_for_an_optional_non_collection_sibling_field() {
let resolver = resolver_anchored_at_document();
assert!(
!resolver.is_array("title"),
"title must not be classified as an array, got: true"
);
}
#[test]
fn is_array_true_for_full_envelope_projected_path() {
let type_defs = vec![
TypeDef {
name: "Envelope".to_string(),
fields: vec![FieldDef {
name: "results".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("Document".to_string()))),
..FieldDef::default()
}],
..TypeDef::default()
},
TypeDef {
name: "Document".to_string(),
fields: vec![FieldDef {
name: "chunks".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("Chunk".to_string()))),
optional: true,
..FieldDef::default()
}],
..TypeDef::default()
},
];
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
let result_fields = set(&["results"]);
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&result_fields,
&HashSet::new(),
&HashSet::new(),
)
.with_ir_collection_map(
FieldResolver::ir_collection_fields(&type_defs),
Some("Envelope".to_string()),
)
.with_ir_result_fields(
FieldResolver::ir_result_field_facts(&type_defs, "rust"),
Some("Envelope".to_string()),
)
.with_ir_fields(reachable, excluded, optional);
assert!(
resolver.is_array("results[0].chunks"),
"is_array must be true for the full projected path results[0].chunks, got: false"
);
assert!(
resolver.is_optional("results[0].chunks"),
"sanity: is_optional was already true for this path before the fix"
);
}
#[test]
fn is_array_stays_false_with_no_anchored_root_type() {
let type_defs = document_type_defs();
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
&HashSet::new(),
)
.with_ir_collection_map(FieldResolver::ir_collection_fields(&type_defs), None)
.with_ir_result_fields(FieldResolver::ir_result_field_facts(&type_defs, "rust"), None)
.with_ir_fields(reachable, excluded, optional);
assert!(
!resolver.is_array("chunks"),
"no anchored root type means no IR answer; must stay false, got: true"
);
}
#[test]
fn is_array_true_from_config_alone_with_no_ir_wired_in() {
let resolver = FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&HashSet::new(),
&set(&["chunks"]),
&HashSet::new(),
);
assert!(
resolver.is_array("chunks"),
"config-declared array field must stay true"
);
}