use std::collections::{HashMap, HashSet};
use crate::core::ir::{FieldDef, TypeDef, TypeRef};
use crate::e2e::field_access::FieldResolver;
use crate::e2e::fixture::Assertion;
pub(crate) const ROOT_TYPE: &str = "Report";
pub(crate) const ENVELOPE_ROOT_TYPE: &str = "Envelope";
pub(crate) const WILDCARD_FIELD: &str = "records[].kind";
pub(crate) const WILDCARD_NAME_FIELD: &str = "records[].name";
fn report_entry_type_defs() -> Vec<TypeDef> {
vec![
TypeDef {
name: ROOT_TYPE.to_string(),
fields: vec![FieldDef {
name: "records".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named("Entry".to_string()))),
..FieldDef::default()
}],
..TypeDef::default()
},
TypeDef {
name: "Entry".to_string(),
fields: vec![
FieldDef {
name: "kind".to_string(),
ty: TypeRef::String,
..FieldDef::default()
},
FieldDef {
name: "name".to_string(),
ty: TypeRef::String,
..FieldDef::default()
},
],
..TypeDef::default()
},
]
}
pub(crate) fn report_resolver(language: &str) -> FieldResolver {
let type_defs = report_entry_type_defs();
let result_field_map = FieldResolver::ir_result_field_facts(&type_defs, language);
let collection_map = FieldResolver::ir_collection_fields(&type_defs);
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
let result_fields = HashSet::from(["records".to_string()]);
FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&result_fields,
&HashSet::new(),
&HashSet::new(),
)
.with_ir_result_fields(result_field_map, Some(ROOT_TYPE.to_string()))
.with_ir_collection_map(collection_map, Some(ROOT_TYPE.to_string()))
.with_ir_fields(reachable, excluded, optional)
}
fn envelope_report_entry_type_defs() -> Vec<TypeDef> {
let mut type_defs = vec![TypeDef {
name: ENVELOPE_ROOT_TYPE.to_string(),
fields: vec![FieldDef {
name: "results".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::Named(ROOT_TYPE.to_string()))),
..FieldDef::default()
}],
..TypeDef::default()
}];
type_defs.extend(report_entry_type_defs());
type_defs
}
pub(crate) fn envelope_resolver(language: &str) -> FieldResolver {
let type_defs = envelope_report_entry_type_defs();
let result_field_map = FieldResolver::ir_result_field_facts(&type_defs, language);
let collection_map = FieldResolver::ir_collection_fields(&type_defs);
let (reachable, excluded, optional) = FieldResolver::ir_field_sets(&type_defs);
let result_fields = HashSet::from(["results".to_string()]);
FieldResolver::new(
&HashMap::new(),
&HashSet::new(),
&result_fields,
&HashSet::new(),
&HashSet::new(),
)
.with_ir_result_fields(result_field_map, Some(ENVELOPE_ROOT_TYPE.to_string()))
.with_ir_collection_map(collection_map, Some(ENVELOPE_ROOT_TYPE.to_string()))
.with_ir_fields(reachable, excluded, optional)
}
pub(crate) fn assert_container_accessor_appears_once(rendered: &str, container_accessor: &str) {
let occurrences = rendered.matches(container_accessor).count();
assert_eq!(
occurrences, 1,
"`{container_accessor}` must appear once (the iteration expression) and not a second time \
inside the closure body, got {occurrences} in: {rendered}"
);
}
pub(crate) fn contains_assertion(field: &str) -> Assertion {
Assertion {
assertion_type: "contains".to_string(),
field: Some(field.to_string()),
value: Some(serde_json::json!("Heading")),
..Default::default()
}
}
pub(crate) fn not_empty_assertion(field: &str) -> Assertion {
Assertion {
assertion_type: "not_empty".to_string(),
field: Some(field.to_string()),
..Default::default()
}
}
pub(crate) fn assert_element_relative(rendered: &str, element_body: &str, container_reapplied: &str) {
assert!(
!rendered.contains(container_reapplied),
"closure body must not re-apply the container path to the element binding \
(`{container_reapplied}` addresses a member the element type does not declare), got: {rendered}"
);
assert!(
rendered.contains(element_body),
"closure body must address the element binding's own field (`{element_body}`), got: {rendered}"
);
}