use super::*;
#[test]
fn max_output_bytes_drops_elements_and_records_it() {
let full = serde_json::to_string(&envelope()).unwrap().len();
let mut s = surface();
s.max_output_bytes = full * 3 / 4;
let shaped = apply(&s, envelope());
assert!(serde_json::to_string(&shaped).unwrap().len() <= s.max_output_bytes);
assert_eq!(shaped["truncated"], json!(true));
assert_eq!(shaped["agent_surface"]["output_truncated"], json!(true));
assert!(shaped["agent_surface"]["dropped"].as_u64().unwrap() > 0);
assert!(results(&shaped).len() < 4);
}
#[test]
fn output_count_describes_what_survived_the_ceiling() {
let full = serde_json::to_string(&envelope()).unwrap().len();
let mut s = surface();
s.max_output_bytes = full * 3 / 4;
let shaped = apply(&s, envelope());
assert_eq!(shaped["agent_surface"]["output_truncated"], json!(true));
let surviving = results(&shaped).len();
let reported = shaped["agent_surface"]["output_count"]
.as_u64()
.expect("output_count must stay present after the ceiling fires")
as usize;
assert_eq!(
reported, surviving,
"output_count reported {reported} beside {surviving} surviving elements"
);
}
#[test]
fn max_output_bytes_falls_back_to_a_parseable_stub() {
let mut s = surface();
s.max_output_bytes = 16;
let shaped = apply(&s, envelope());
assert_eq!(shaped["truncated"], json!(true));
assert_eq!(shaped["truncated_reason"], json!("max_output_bytes"));
let text = serde_json::to_string(&shaped).unwrap();
assert!(serde_json::from_str::<Value>(&text).is_ok());
}
#[test]
fn max_output_bytes_leaves_a_fitting_envelope_alone() {
let mut s = surface();
s.max_output_bytes = 1_000_000;
let shaped = apply(&s, envelope());
assert_eq!(results(&shaped).len(), 4);
assert!(shaped.get("truncated").is_none());
}
#[test]
fn budget_returns_real_rows_instead_of_the_stub_when_an_alias_inflates_the_envelope() {
let row = json!({ "name": "alpha", "snippet": "x".repeat(120) });
let items: Vec<Value> = (0..30).map(|_| row.clone()).collect();
let value = json!({
"total_count": 30,
"items": items,
"memories": items,
"elapsed_ms": 1
});
let mut s = surface_for("list");
s.select = vec!["name".into()];
s.max_output_bytes = 800;
let shaped = apply(&s, value);
let emitted = serde_json::to_string(&shaped).unwrap();
assert!(emitted.len() <= s.max_output_bytes, "ceiling honoured");
assert_ne!(
shaped["truncated_reason"],
json!("max_output_bytes"),
"the stub is never an acceptable answer here: {shaped}"
);
let rows = shaped["items"]
.as_array()
.unwrap_or_else(|| panic!("items must survive the ceiling: {shaped}"));
assert!(
!rows.is_empty(),
"real rows must reach the caller: {shaped}"
);
assert!(shaped.get("memories").is_none());
}
#[test]
fn a_large_secondary_array_no_longer_forces_the_stub() {
let nodes: Vec<Value> = (0..50).map(|i| json!({ "id": i })).collect();
let edges: Vec<Value> = (0..500)
.map(|i| json!({ "from": i, "to": i + 1, "relation": "depends-on" }))
.collect();
let mut s = surface();
s.max_output_bytes = 900;
let shaped = apply(&s, json!({ "nodes": nodes, "edges": edges }));
assert!(
shaped.get("truncated_reason").is_none(),
"the envelope collapsed into the stub: {shaped}"
);
assert!(
!shaped["nodes"].as_array().unwrap().is_empty(),
"nodes was emptied even though trimming edges made room"
);
assert_eq!(
shaped["agent_surface"]["output_truncated"],
json!(true),
"dropping data is never silent"
);
}
#[test]
fn the_stub_reports_the_requested_ceiling_not_the_discounted_one() {
let mut s = surface();
s.max_output_bytes = 200;
let results: Vec<Value> = (0..20)
.map(|i| json!({ "name": format!("memory-{i}") }))
.collect();
let shaped = apply(&s, json!({ "results": results, "query": "q".repeat(400) }));
assert_eq!(
shaped["truncated_reason"], "max_output_bytes",
"this case must reach the stub: {shaped}"
);
assert_eq!(
shaped["max_output_bytes"],
json!(200),
"the stub echoed the internally discounted budget"
);
}
#[test]
fn the_prefix_scan_never_overshoots_the_ceiling() {
let results: Vec<Value> = (0..80)
.map(|i| json!({ "name": format!("memory-{i}"), "score": i }))
.collect();
for ceiling in [200usize, 300, 400, 500, 700, 900, 1200, 2000, 4000] {
let mut s = surface();
s.max_output_bytes = ceiling;
let shaped = apply(&s, json!({ "results": results.clone(), "query": "x" }));
let encoded = serde_json::to_string(&shaped).expect("shaped envelope serializes");
assert!(
encoded.len() <= ceiling,
"ceiling {ceiling} produced {} bytes: {shaped}",
encoded.len()
);
}
}