use super::*;
use crate::core::config::e2e::CallConfig;
use crate::core::ir::{FieldDef, FunctionDef, TypeDef, TypeRef};
use std::collections::HashSet;
fn docs_fixture(presentation_operations: serde_json::Value) -> Fixture {
serde_json::from_value(serde_json::json!({
"id": "sample_fixture",
"description": "Sample fixture",
"input": {},
"docs": {
"topic": "smoke",
"stem": "sample_fixture",
"presentation": {"operations": presentation_operations},
}
}))
.expect("fixture must parse")
}
fn config() -> E2eConfig {
E2eConfig {
call: CallConfig {
function: "extract_batch".into(),
result_var: "result".into(),
..CallConfig::default()
},
result_fields: HashSet::from(["results".to_string()]),
..E2eConfig::default()
}
}
fn field(name: &str, ty: TypeRef) -> FieldDef {
FieldDef {
name: name.to_string(),
ty,
..FieldDef::default()
}
}
fn type_defs() -> Vec<TypeDef> {
vec![
TypeDef {
name: "ExtractionResult".to_string(),
fields: vec![
field(
"results",
TypeRef::Optional(Box::new(TypeRef::Vec(Box::new(TypeRef::Named(
"ExtractedDocument".to_string(),
))))),
),
field(
"errors",
TypeRef::Optional(Box::new(TypeRef::Vec(Box::new(TypeRef::Named(
"ExtractionError".to_string(),
))))),
),
],
..TypeDef::default()
},
TypeDef {
name: "ExtractedDocument".to_string(),
fields: vec![field("content", TypeRef::Optional(Box::new(TypeRef::String)))],
..TypeDef::default()
},
TypeDef {
name: "ExtractionError".to_string(),
fields: vec![field("message", TypeRef::String)],
..TypeDef::default()
},
]
}
fn extract_batch_returning(type_name: &str) -> Vec<FunctionDef> {
vec![FunctionDef {
name: "extract_batch".to_string(),
return_type: TypeRef::Named(type_name.to_string()),
..FunctionDef::default()
}]
}
fn resolved(fixture: &Fixture, language: &str) -> Vec<PresentationOperation> {
resolve(
fixture,
&config(),
language,
&type_defs(),
&extract_batch_returning("ExtractionResult"),
)
}
#[test]
fn an_iterate_field_that_collides_with_a_result_nested_path_resolves_against_the_element_type() {
let fixture = docs_fixture(serde_json::json!([{
"op": "iterate",
"path": "results",
"item": "item",
"fields": ["content"],
}]));
for language in ["python", "rust"] {
let operations = resolved(&fixture, language);
assert_eq!(operations.len(), 1);
assert_eq!(operations[0].fields, vec!["item.content".to_string()]);
}
}
#[test]
fn the_typescript_rendering_does_not_reintroduce_the_results_path_under_the_loop_item() {
let fixture = docs_fixture(serde_json::json!([{
"op": "iterate",
"path": "results",
"item": "item",
"fields": ["content"],
}]));
let operations = resolved(&fixture, "node");
assert_eq!(operations.len(), 1);
assert_eq!(operations[0].fields, vec!["item.content".to_string()]);
}
#[test]
fn an_iterate_field_with_no_result_fields_entry_for_its_collection_stays_flat() {
let fixture = docs_fixture(serde_json::json!([{
"op": "iterate",
"path": "errors",
"item": "item",
"fields": ["message"],
}]));
for language in ["python", "rust", "node"] {
let operations = resolved(&fixture, language);
assert_eq!(operations.len(), 1);
assert_eq!(
operations[0].fields,
vec!["item.message".to_string()],
"a per-item field whose collection has no `result_fields` entry must never be \
rewritten through the result type, in {language}"
);
}
}