use super::*;
use crate::core::config::ResolvedCrateConfig;
use crate::e2e::config::{CallConfig, E2eConfig};
use crate::e2e::fixture::Fixture;
#[test]
fn an_iterate_item_named_result_is_renamed_to_avoid_shadowing_the_call_result() {
let fixture: Fixture = serde_json::from_value(serde_json::json!({
"id": "batch_present", "description": "Present a batch of results", "input": null,
"docs": {"topic": "guides", "presentation": {"operations": [
{"op": "iterate", "path": "results", "item": "result", "fields": ["label"]}
]}}
}))
.expect("fixture");
let e2e = E2eConfig {
call: CallConfig {
function: "process_batch".into(),
result_var: "result".into(),
..CallConfig::default()
},
result_fields: ["results".to_string()].into_iter().collect(),
..E2eConfig::default()
};
let config = ResolvedCrateConfig {
name: "sample_core".into(),
..ResolvedCrateConfig::default()
};
let body = render_snippet_body(&fixture, &e2e, &config, &[], &[]).expect("snippet renders");
assert!(
body.contains("var result = SampleCoreConverter.ProcessBatch();"),
"{body}"
);
assert!(
!body.contains("foreach (var result in"),
"the loop variable must not shadow the outer `result` binding (CS0136):\n{body}"
);
assert!(body.contains("foreach (var resultItem in result.Results)"), "{body}");
assert!(body.contains("Console.WriteLine(resultItem.Label);"), "{body}");
}
#[test]
fn disambiguation_skips_show_operations_and_leaves_non_colliding_siblings_alone() {
fn iterate_op(item: &str) -> crate::e2e::codegen::presentation::PresentationOperation {
crate::e2e::codegen::presentation::PresentationOperation {
kind: "iterate",
expression: "result.Items".to_string(),
item: item.to_string(),
fields: vec![format!("{item}.Label")],
optional: false,
display: false,
destructure_source: String::new(),
destructure_item: String::new(),
shown_optional: false,
field_optionals: vec![false],
field_displays: vec![false],
}
}
let show = crate::e2e::codegen::presentation::PresentationOperation {
kind: "show",
expression: "result.Count".to_string(),
item: String::new(),
fields: Vec::new(),
optional: false,
display: false,
destructure_source: String::new(),
destructure_item: String::new(),
shown_optional: false,
field_optionals: Vec::new(),
field_displays: Vec::new(),
};
let operations = vec![show, iterate_op("result"), iterate_op("resultItem")];
let disambiguated = disambiguate_presentation_items(operations, "result", false);
assert_eq!(
disambiguated[0].item, "",
"a show operation's item must be left untouched"
);
assert_eq!(
disambiguated[1].item, "resultItem",
"must rename to avoid shadowing the outer `result`"
);
assert_eq!(disambiguated[1].fields, vec!["resultItem.Label".to_string()]);
assert_eq!(
disambiguated[2].item, "resultItem",
"a sibling loop's own name is not a collision"
);
}