use super::super::assertions::render_assertion;
use super::tests::*;
use crate::e2e::field_access::FieldResolver;
fn envelope_and_document_type_defs() -> Vec<crate::core::ir::TypeDef> {
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
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()))),
..FieldDef::default()
}],
..TypeDef::default()
},
]
}
fn resolver_anchored_at(root_type: Option<&str>) -> FieldResolver {
let type_defs = envelope_and_document_type_defs();
let map = FieldResolver::ir_result_field_facts(&type_defs, "rust");
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
empty_resolver()
.with_ir_result_fields(map, root_type.map(str::to_string))
.with_ir_fields(reachable, excluded, optional)
}
fn render_chunks_have_content_call(resolver: &FieldResolver) -> String {
let assertion = make_assertion("is_true", Some("chunks_have_content"), None);
let mut out = String::new();
render_assertion(
&mut out,
&assertion,
"result",
"my_mod",
"dep",
false,
&[],
resolver,
false,
false,
false,
false,
false,
None,
);
out
}
#[test]
fn chunks_have_content_refused_when_call_root_lacks_chunks() {
let resolver = resolver_anchored_at(Some("Envelope"));
let out = render_chunks_have_content_call(&resolver);
assert!(
!out.contains("result.chunks"),
"must not hardcode result.chunks against a root type that declares no such field, got: {out}"
);
assert!(out.contains("// skipped:"), "got: {out}");
}
#[test]
fn chunks_have_content_still_renders_when_call_root_declares_chunks() {
let resolver = resolver_anchored_at(Some("Document"));
let out = render_chunks_have_content_call(&resolver);
assert!(out.contains("result.chunks"), "got: {out}");
assert!(!out.contains("// skipped:"), "got: {out}");
}
#[test]
fn chunks_have_content_renders_when_no_root_type_is_anchored() {
let resolver = resolver_anchored_at(None);
let out = render_chunks_have_content_call(&resolver);
assert!(out.contains("result.chunks"), "got: {out}");
assert!(!out.contains("// skipped:"), "got: {out}");
}
mod envelope_projection {
use super::{empty_resolver, make_assertion, render_assertion};
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
use crate::e2e::field_access::FieldResolver;
use std::collections::HashSet;
fn envelope_document_type_defs() -> Vec<TypeDef> {
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()))),
..FieldDef::default()
}],
..TypeDef::default()
},
]
}
fn envelope_resolver_with_result_fields(result_fields: &[&str]) -> FieldResolver {
let type_defs = envelope_document_type_defs();
let result_field_map = FieldResolver::ir_result_field_facts(&type_defs, "rust");
let collection_map = FieldResolver::ir_collection_fields(&type_defs);
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
let result_fields: HashSet<String> = result_fields.iter().map(|s| s.to_string()).collect();
FieldResolver::new(
&std::collections::HashMap::new(),
&HashSet::new(),
&result_fields,
&HashSet::new(),
&HashSet::new(),
)
.with_ir_result_fields(result_field_map, Some("Envelope".to_string()))
.with_ir_collection_map(collection_map, Some("Envelope".to_string()))
.with_ir_fields(reachable, excluded, optional)
}
fn render_chunks_have_content(resolver: &FieldResolver) -> String {
let assertion = make_assertion("is_true", Some("chunks_have_content"), None);
let mut out = String::new();
render_assertion(
&mut out,
&assertion,
"result",
"my_mod",
"dep",
false,
&[],
resolver,
false,
false,
false,
false,
false,
None,
);
out
}
#[test]
fn synthetic_and_generic_paths_agree_on_the_same_accessor() {
let resolver = envelope_resolver_with_result_fields(&["results"]);
let generic_accessor = resolver.accessor("results[0].chunks", "rust", "result");
assert_eq!(
generic_accessor, "result.results[0].chunks",
"sanity: the generic accessor for the real path must include the [0] hop, got: {generic_accessor}"
);
let synthetic_out = render_chunks_have_content(&resolver);
assert!(
synthetic_out.contains(&generic_accessor),
"synthetic and generic paths disagree — synthetic must contain `{generic_accessor}`, got: {synthetic_out}"
);
assert!(!synthetic_out.contains("// skipped:"), "got: {synthetic_out}");
}
#[test]
fn refuses_when_no_result_fields_prefix_reaches_chunks_through_the_full_render_path() {
let resolver = envelope_resolver_with_result_fields(&["not_a_real_field"]);
let out = render_chunks_have_content(&resolver);
assert!(
!out.contains("result.chunks") && !out.contains("result.not_a_real_field"),
"must not emit a non-compiling accessor for a genuinely unreachable field, got: {out}"
);
assert!(out.contains("// skipped:"), "got: {out}");
}
#[test]
fn a_root_declaring_chunks_directly_stays_direct_even_with_result_fields_present() {
let type_defs = vec![TypeDef {
name: "Document".to_string(),
fields: vec![FieldDef {
name: "chunks".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("Chunk".to_string()))),
..FieldDef::default()
}],
..TypeDef::default()
}];
let result_field_map = FieldResolver::ir_result_field_facts(&type_defs, "rust");
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
let result_fields: HashSet<String> = ["unrelated".to_string()].into_iter().collect();
let resolver = FieldResolver::new(
&std::collections::HashMap::new(),
&HashSet::new(),
&result_fields,
&HashSet::new(),
&HashSet::new(),
)
.with_ir_result_fields(result_field_map, Some("Document".to_string()))
.with_ir_fields(reachable, excluded, optional);
let out = render_chunks_have_content(&resolver);
assert!(out.contains("result.chunks"), "got: {out}");
assert!(!out.contains("// skipped:"), "got: {out}");
}
#[test]
fn no_anchored_root_stays_direct_even_with_result_fields_present() {
let resolver = empty_resolver();
let _ = &resolver; let out = render_chunks_have_content(&resolver);
assert!(out.contains("result.chunks"), "got: {out}");
assert!(!out.contains("// skipped:"), "got: {out}");
}
}